@@ -104,7 +104,7 @@
// invokeGuardedCallback uses a try-catch, all user exceptions are treated
// like caught exceptions, and the DevTools won't pause unless the developer
// takes the extra step of enabling pause on caught exceptions. This is
- // untintuitive, though, because even though React has caught the error, from
+ // unintuitive, though, because even though React has caught the error, from
// the developer's perspective, the error is uncaught.
//
// To preserve the expected "Pause on exceptions" behavior, we don't use a
@@ -1090,6 +1090,7 @@
var SimpleMemoComponent = 15;
var LazyComponent = 16;
var IncompleteClassComponent = 17;
+var DehydratedSuspenseComponent = 18;
function getParent(inst) {
do {
@@ -2840,6 +2841,15 @@
var ReactSharedInternals =
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
+// Prevent newer renderers from RTE when used with older react package versions.
+// Current owner and dispatcher used to share the same ref,
+// but PR #14548 split them out to better support the react-debug-tools package.
+if (!ReactSharedInternals.hasOwnProperty("ReactCurrentDispatcher")) {
+ ReactSharedInternals.ReactCurrentDispatcher = {
+ current: null
+ };
+}
+
// The Symbol used to tag the ReactElement-like types. If there is no native Symbol
// nor polyfill, then a plain number is used for performance.
var hasSymbol = typeof Symbol === "function" && Symbol.for;
@@ -3715,6 +3725,19 @@
}
}
+var debugRenderPhaseSideEffects = false;
+var debugRenderPhaseSideEffectsForStrictMode = false;
+var enableUserTimingAPI = true;
+var replayFailedUnitOfWorkWithInvokeGuardedCallback = true;
+var warnAboutDeprecatedLifecycles = false;
+var enableProfilerTimer = true;
+var enableSchedulerTracing = true;
+var enableSuspenseServerRenderer = false;
+
+var warnAboutDeprecatedSetNativeProps = false;
+
+// Only used in www builds.
+
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
@@ -3780,6 +3803,15 @@
nativeProps
) {
{
+ if (warnAboutDeprecatedSetNativeProps) {
+ warningWithoutStack$1(
+ false,
+ "Warning: Calling ref.setNativeProps(nativeProps) " +
+ "is deprecated and will be removed in a future release. " +
+ "Use the setNativeProps export from the react-native package instead." +
+ "\n\timport {setNativeProps} from 'react-native';\n\tsetNativeProps(ref, nativeProps);\n"
+ );
+ }
warnForStyleProps(nativeProps, this.viewConfig.validAttributes);
}
@@ -3883,21 +3915,31 @@
}
// Hydration (when unsupported)
+
var supportsHydration = false;
var canHydrateInstance = shim$1;
var canHydrateTextInstance = shim$1;
+var canHydrateSuspenseInstance = shim$1;
+var isSuspenseInstancePending = shim$1;
+var isSuspenseInstanceFallback = shim$1;
+var registerSuspenseInstanceRetry = shim$1;
var getNextHydratableSibling = shim$1;
var getFirstHydratableChild = shim$1;
var hydrateInstance = shim$1;
var hydrateTextInstance = shim$1;
+var getNextHydratableInstanceAfterSuspenseInstance = shim$1;
+var clearSuspenseBoundary = shim$1;
+var clearSuspenseBoundaryFromContainer = shim$1;
var didNotMatchHydratedContainerTextInstance = shim$1;
var didNotMatchHydratedTextInstance = shim$1;
var didNotHydrateContainerInstance = shim$1;
var didNotHydrateInstance = shim$1;
var didNotFindHydratableContainerInstance = shim$1;
var didNotFindHydratableContainerTextInstance = shim$1;
+var didNotFindHydratableContainerSuspenseInstance = shim$1;
var didNotFindHydratableInstance = shim$1;
var didNotFindHydratableTextInstance = shim$1;
+var didNotFindHydratableSuspenseInstance = shim$1;
// Modules provided by RN:
// Unused
@@ -4082,6 +4124,8 @@
var scheduleTimeout = setTimeout;
var cancelTimeout = clearTimeout;
var noTimeout = -1;
+var schedulePassiveEffects = scheduleDeferredCallback$$1;
+var cancelPassiveEffects = cancelDeferredCallback$$1;
function shouldDeprioritizeSubtree(type, props) {
return false;
@@ -4401,17 +4445,6 @@
}
}
-var debugRenderPhaseSideEffects = false;
-var debugRenderPhaseSideEffectsForStrictMode = false;
-var enableHooks = false;
-var enableUserTimingAPI = true;
-var replayFailedUnitOfWorkWithInvokeGuardedCallback = true;
-var warnAboutDeprecatedLifecycles = false;
-var enableProfilerTimer = true;
-var enableSchedulerTracing = true;
-
-// Only used in www builds.
-
// Prefix measurements so that it's possible to filter them.
// Longer prefixes are hard to read in DevTools.
var reactEmoji = "\u269B";
@@ -4683,7 +4716,8 @@
}
fiber._debugIsCurrentlyTiming = false;
var warning =
- fiber.tag === SuspenseComponent
+ fiber.tag === SuspenseComponent ||
+ fiber.tag === DehydratedSuspenseComponent
? "Rendering was suspended"
: "An error was thrown inside this error boundary";
endFiberMark(fiber, null, warning);
@@ -5407,7 +5441,7 @@
this.memoizedProps = null;
this.updateQueue = null;
this.memoizedState = null;
- this.firstContextDependency = null;
+ this.contextDependencies = null;
this.mode = mode;
@@ -5424,14 +5458,16 @@
this.alternate = null;
if (enableProfilerTimer) {
- // Note: The following is done to avoid a v8 deopt.
+ // Note: The following is done to avoid a v8 performance cliff.
//
- // It is important to initialize the fields below with doubles.
- // Otherwise Fibers will deopt and end up having separate shapes when
- // doubles are later assigned to fields that initially contained smis.
- // This is a bug in v8 having something to do with Object.preventExtension().
+ // Initializing the fields below to smis and later updating them with
+ // double values will cause Fibers to end up having separate shapes.
+ // This behavior/bug has something to do with Object.preventExtension().
+ // Fortunately this only impacts DEV builds.
+ // Unfortunately it makes React unusably slow for some applications.
+ // To work around this, initialize the fields below with doubles.
//
- // Learn more about this deopt here:
+ // Learn more about this here:
// https://github.com/facebook/react/issues/14365
// https://bugs.chromium.org/p/v8/issues/detail?id=8538
this.actualDuration = Number.NaN;
@@ -5440,7 +5476,8 @@
this.treeBaseDuration = Number.NaN;
// It's okay to replace the initial doubles with smis after initialization.
- // This simplifies other profiler code and doesn't trigger the deopt.
+ // This won't trigger the performance cliff mentioned above,
+ // and it simplifies other profiler code (including DevTools).
this.actualDuration = 0;
this.actualStartTime = -1;
this.selfBaseDuration = 0;
@@ -5561,7 +5598,7 @@
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.memoizedState = current.memoizedState;
workInProgress.updateQueue = current.updateQueue;
- workInProgress.firstContextDependency = current.firstContextDependency;
+ workInProgress.contextDependencies = current.contextDependencies;
// These will be overridden during the parent's reconciliation
workInProgress.sibling = current.sibling;
@@ -5827,7 +5864,7 @@
target.memoizedProps = source.memoizedProps;
target.updateQueue = source.updateQueue;
target.memoizedState = source.memoizedState;
- target.firstContextDependency = source.firstContextDependency;
+ target.contextDependencies = source.contextDependencies;
target.mode = source.mode;
target.effectTag = source.effectTag;
target.nextEffect = source.nextEffect;
@@ -5880,6 +5917,8 @@
latestSuspendedTime: NoWork,
latestPingedTime: NoWork,
+ pingCache: null,
+
didError: false,
pendingCommitExpirationTime: NoWork,
@@ -5903,6 +5942,8 @@
containerInfo: containerInfo,
pendingChildren: null,
+ pingCache: null,
+
earliestPendingTime: NoWork,
latestPendingTime: NoWork,
earliestSuspendedTime: NoWork,
@@ -6052,7 +6093,7 @@
lifecycleWarningsMap,
strictRoot
) {
- var lifecyclesWarningMesages = [];
+ var lifecyclesWarningMessages = [];
Object.keys(lifecycleWarningsMap).forEach(function(lifecycle) {
var lifecycleWarnings = lifecycleWarningsMap[lifecycle];
@@ -6067,7 +6108,7 @@
var suggestion = LIFECYCLE_SUGGESTIONS[lifecycle];
var sortedComponentNames = setToSortedString(componentNames);
- lifecyclesWarningMesages.push(
+ lifecyclesWarningMessages.push(
formatted +
": Please update the following components to use " +
(suggestion + " instead: " + sortedComponentNames)
@@ -6075,7 +6116,7 @@
}
});
- if (lifecyclesWarningMesages.length > 0) {
+ if (lifecyclesWarningMessages.length > 0) {
var strictRootComponentStack = getStackByFiberInDevAndProd(strictRoot);
warningWithoutStack$1(
@@ -6085,7 +6126,7 @@
"\n\nLearn more about this warning here:" +
"\nhttps://fb.me/react-strict-mode-warnings",
strictRootComponentStack,
- lifecyclesWarningMesages.join("\n\n")
+ lifecyclesWarningMessages.join("\n\n")
);
}
});
@@ -6386,6 +6427,10 @@
return;
}
+ if (earliestRemainingTime < root.latestPingedTime) {
+ root.latestPingedTime = NoWork;
+ }
+
// Let's see if the previous latest known pending level was just flushed.
var latestPendingTime = root.latestPendingTime;
if (latestPendingTime !== NoWork) {
@@ -6521,10 +6566,8 @@
}
function clearPing(root, completedTime) {
- // TODO: Track whether the root was pinged during the render phase. If so,
- // we need to make sure we don't lose track of it.
var latestPingedTime = root.latestPingedTime;
- if (latestPingedTime !== NoWork && latestPingedTime >= completedTime) {
+ if (latestPingedTime >= completedTime) {
root.latestPingedTime = NoWork;
}
}
@@ -6585,561 +6628,6 @@
root.expirationTime = expirationTime;
}
-// UpdateQueue is a linked list of prioritized updates.
-//
-// Like fibers, update queues come in pairs: a current queue, which represents
-// the visible state of the screen, and a work-in-progress queue, which is
-// can be mutated and processed asynchronously before it is committed — a form
-// of double buffering. If a work-in-progress render is discarded before
-// finishing, we create a new work-in-progress by cloning the current queue.
-//
-// Both queues share a persistent, singly-linked list structure. To schedule an
-// update, we append it to the end of both queues. Each queue maintains a
-// pointer to first update in the persistent list that hasn't been processed.
-// The work-in-progress pointer always has a position equal to or greater than
-// the current queue, since we always work on that one. The current queue's
-// pointer is only updated during the commit phase, when we swap in the
-// work-in-progress.
-//
-// For example:
-//
-// Current pointer: A - B - C - D - E - F
-// Work-in-progress pointer: D - E - F
-// ^
-// The work-in-progress queue has
-// processed more updates than current.
-//
-// The reason we append to both queues is because otherwise we might drop
-// updates without ever processing them. For example, if we only add updates to
-// the work-in-progress queue, some updates could be lost whenever a work-in
-// -progress render restarts by cloning from current. Similarly, if we only add
-// updates to the current queue, the updates will be lost whenever an already
-// in-progress queue commits and swaps with the current queue. However, by
-// adding to both queues, we guarantee that the update will be part of the next
-// work-in-progress. (And because the work-in-progress queue becomes the
-// current queue once it commits, there's no danger of applying the same
-// update twice.)
-//
-// Prioritization
-// --------------
-//
-// Updates are not sorted by priority, but by insertion; new updates are always
-// appended to the end of the list.
-//
-// The priority is still important, though. When processing the update queue
-// during the render phase, only the updates with sufficient priority are
-// included in the result. If we skip an update because it has insufficient
-// priority, it remains in the queue to be processed later, during a lower
-// priority render. Crucially, all updates subsequent to a skipped update also
-// remain in the queue *regardless of their priority*. That means high priority
-// updates are sometimes processed twice, at two separate priorities. We also
-// keep track of a base state, that represents the state before the first
-// update in the queue is applied.
-//
-// For example:
-//
-// Given a base state of '', and the following queue of updates
-//
-// A1 - B2 - C1 - D2
-//
-// where the number indicates the priority, and the update is applied to the
-// previous state by appending a letter, React will process these updates as
-// two separate renders, one per distinct priority level:
-//
-// First render, at priority 1:
-// Base state: ''
-// Updates: [A1, C1]
-// Result state: 'AC'
-//
-// Second render, at priority 2:
-// Base state: 'A' <- The base state does not include C1,
-// because B2 was skipped.
-// Updates: [B2, C1, D2] <- C1 was rebased on top of B2
-// Result state: 'ABCD'
-//
-// Because we process updates in insertion order, and rebase high priority
-// updates when preceding updates are skipped, the final result is deterministic
-// regardless of priority. Intermediate state may vary according to system
-// resources, but the final state is always the same.
-
-var UpdateState = 0;
-var ReplaceState = 1;
-var ForceUpdate = 2;
-var CaptureUpdate = 3;
-
-// Global state that is reset at the beginning of calling `processUpdateQueue`.
-// It should only be read right after calling `processUpdateQueue`, via
-// `checkHasForceUpdateAfterProcessing`.
-var hasForceUpdate = false;
-
-var didWarnUpdateInsideUpdate = void 0;
-var currentlyProcessingQueue = void 0;
-var resetCurrentlyProcessingQueue = void 0;
-{
- didWarnUpdateInsideUpdate = false;
- currentlyProcessingQueue = null;
- resetCurrentlyProcessingQueue = function() {
- currentlyProcessingQueue = null;
- };
-}
-
-function createUpdateQueue(baseState) {
- var queue = {
- baseState: baseState,
- firstUpdate: null,
- lastUpdate: null,
- firstCapturedUpdate: null,
- lastCapturedUpdate: null,
- firstEffect: null,
- lastEffect: null,
- firstCapturedEffect: null,
- lastCapturedEffect: null
- };
- return queue;
-}
-
-function cloneUpdateQueue(currentQueue) {
- var queue = {
- baseState: currentQueue.baseState,
- firstUpdate: currentQueue.firstUpdate,
- lastUpdate: currentQueue.lastUpdate,
-
- // TODO: With resuming, if we bail out and resuse the child tree, we should
- // keep these effects.
- firstCapturedUpdate: null,
- lastCapturedUpdate: null,
-
- firstEffect: null,
- lastEffect: null,
-
- firstCapturedEffect: null,
- lastCapturedEffect: null
- };
- return queue;
-}
-
-function createUpdate(expirationTime) {
- return {
- expirationTime: expirationTime,
-
- tag: UpdateState,
- payload: null,
- callback: null,
-
- next: null,
- nextEffect: null
- };
-}
-
-function appendUpdateToQueue(queue, update) {
- // Append the update to the end of the list.
- if (queue.lastUpdate === null) {
- // Queue is empty
- queue.firstUpdate = queue.lastUpdate = update;
- } else {
- queue.lastUpdate.next = update;
- queue.lastUpdate = update;
- }
-}
-
-function enqueueUpdate(fiber, update) {
- // Update queues are created lazily.
- var alternate = fiber.alternate;
- var queue1 = void 0;
- var queue2 = void 0;
- if (alternate === null) {
- // There's only one fiber.
- queue1 = fiber.updateQueue;
- queue2 = null;
- if (queue1 === null) {
- queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
- }
- } else {
- // There are two owners.
- queue1 = fiber.updateQueue;
- queue2 = alternate.updateQueue;
- if (queue1 === null) {
- if (queue2 === null) {
- // Neither fiber has an update queue. Create new ones.
- queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
- queue2 = alternate.updateQueue = createUpdateQueue(
- alternate.memoizedState
- );
- } else {
- // Only one fiber has an update queue. Clone to create a new one.
- queue1 = fiber.updateQueue = cloneUpdateQueue(queue2);
- }
- } else {
- if (queue2 === null) {
- // Only one fiber has an update queue. Clone to create a new one.
- queue2 = alternate.updateQueue = cloneUpdateQueue(queue1);
- } else {
- // Both owners have an update queue.
- }
- }
- }
- if (queue2 === null || queue1 === queue2) {
- // There's only a single queue.
- appendUpdateToQueue(queue1, update);
- } else {
- // There are two queues. We need to append the update to both queues,
- // while accounting for the persistent structure of the list — we don't
- // want the same update to be added multiple times.
- if (queue1.lastUpdate === null || queue2.lastUpdate === null) {
- // One of the queues is not empty. We must add the update to both queues.
- appendUpdateToQueue(queue1, update);
- appendUpdateToQueue(queue2, update);
- } else {
- // Both queues are non-empty. The last update is the same in both lists,
- // because of structural sharing. So, only append to one of the lists.
- appendUpdateToQueue(queue1, update);
- // But we still need to update the `lastUpdate` pointer of queue2.
- queue2.lastUpdate = update;
- }
- }
-
- {
- if (
- fiber.tag === ClassComponent &&
- (currentlyProcessingQueue === queue1 ||
- (queue2 !== null && currentlyProcessingQueue === queue2)) &&
- !didWarnUpdateInsideUpdate
- ) {
- warningWithoutStack$1(
- false,
- "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."
- );
- didWarnUpdateInsideUpdate = true;
- }
- }
-}
-
-function enqueueCapturedUpdate(workInProgress, update) {
- // Captured updates go into a separate list, and only on the work-in-
- // progress queue.
- var workInProgressQueue = workInProgress.updateQueue;
- if (workInProgressQueue === null) {
- workInProgressQueue = workInProgress.updateQueue = createUpdateQueue(
- workInProgress.memoizedState
- );
- } else {
- // TODO: I put this here rather than createWorkInProgress so that we don't
- // clone the queue unnecessarily. There's probably a better way to
- // structure this.
- workInProgressQueue = ensureWorkInProgressQueueIsAClone(
- workInProgress,
- workInProgressQueue
- );
- }
-
- // Append the update to the end of the list.
- if (workInProgressQueue.lastCapturedUpdate === null) {
- // This is the first render phase update
- workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update;
- } else {
- workInProgressQueue.lastCapturedUpdate.next = update;
- workInProgressQueue.lastCapturedUpdate = update;
- }
-}
-
-function ensureWorkInProgressQueueIsAClone(workInProgress, queue) {
- var current = workInProgress.alternate;
- if (current !== null) {
- // If the work-in-progress queue is equal to the current queue,
- // we need to clone it first.
- if (queue === current.updateQueue) {
- queue = workInProgress.updateQueue = cloneUpdateQueue(queue);
- }
- }
- return queue;
-}
-
-function getStateFromUpdate(
- workInProgress,
- queue,
- update,
- prevState,
- nextProps,
- instance
-) {
- switch (update.tag) {
- case ReplaceState: {
- var _payload = update.payload;
- if (typeof _payload === "function") {
- // Updater function
- {
- if (
- debugRenderPhaseSideEffects ||
- (debugRenderPhaseSideEffectsForStrictMode &&
- workInProgress.mode & StrictMode)
- ) {
- _payload.call(instance, prevState, nextProps);
- }
- }
- return _payload.call(instance, prevState, nextProps);
- }
- // State object
- return _payload;
- }
- case CaptureUpdate: {
- workInProgress.effectTag =
- (workInProgress.effectTag & ~ShouldCapture) | DidCapture;
- }
- // Intentional fallthrough
- case UpdateState: {
- var _payload2 = update.payload;
- var partialState = void 0;
- if (typeof _payload2 === "function") {
- // Updater function
- {
- if (
- debugRenderPhaseSideEffects ||
- (debugRenderPhaseSideEffectsForStrictMode &&
- workInProgress.mode & StrictMode)
- ) {
- _payload2.call(instance, prevState, nextProps);
- }
- }
- partialState = _payload2.call(instance, prevState, nextProps);
- } else {
- // Partial state object
- partialState = _payload2;
- }
- if (partialState === null || partialState === undefined) {
- // Null and undefined are treated as no-ops.
- return prevState;
- }
- // Merge the partial state and the previous state.
- return Object.assign({}, prevState, partialState);
- }
- case ForceUpdate: {
- hasForceUpdate = true;
- return prevState;
- }
- }
- return prevState;
-}
-
-function processUpdateQueue(
- workInProgress,
- queue,
- props,
- instance,
- renderExpirationTime
-) {
- hasForceUpdate = false;
-
- queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);
-
- {
- currentlyProcessingQueue = queue;
- }
-
- // These values may change as we process the queue.
- var newBaseState = queue.baseState;
- var newFirstUpdate = null;
- var newExpirationTime = NoWork;
-
- // Iterate through the list of updates to compute the result.
- var update = queue.firstUpdate;
- var resultState = newBaseState;
- while (update !== null) {
- var updateExpirationTime = update.expirationTime;
- if (updateExpirationTime < renderExpirationTime) {
- // This update does not have sufficient priority. Skip it.
- if (newFirstUpdate === null) {
- // This is the first skipped update. It will be the first update in
- // the new list.
- newFirstUpdate = update;
- // Since this is the first update that was skipped, the current result
- // is the new base state.
- newBaseState = resultState;
- }
- // Since this update will remain in the list, update the remaining
- // expiration time.
- if (newExpirationTime < updateExpirationTime) {
- newExpirationTime = updateExpirationTime;
- }
- } else {
- // This update does have sufficient priority. Process it and compute
- // a new result.
- resultState = getStateFromUpdate(
- workInProgress,
- queue,
- update,
- resultState,
- props,
- instance
- );
- var _callback = update.callback;
- if (_callback !== null) {
- workInProgress.effectTag |= Callback;
- // Set this to null, in case it was mutated during an aborted render.
- update.nextEffect = null;
- if (queue.lastEffect === null) {
- queue.firstEffect = queue.lastEffect = update;
- } else {
- queue.lastEffect.nextEffect = update;
- queue.lastEffect = update;
- }
- }
- }
- // Continue to the next update.
- update = update.next;
- }
-
- // Separately, iterate though the list of captured updates.
- var newFirstCapturedUpdate = null;
- update = queue.firstCapturedUpdate;
- while (update !== null) {
- var _updateExpirationTime = update.expirationTime;
- if (_updateExpirationTime < renderExpirationTime) {
- // This update does not have sufficient priority. Skip it.
- if (newFirstCapturedUpdate === null) {
- // This is the first skipped captured update. It will be the first
- // update in the new list.
- newFirstCapturedUpdate = update;
- // If this is the first update that was skipped, the current result is
- // the new base state.
- if (newFirstUpdate === null) {
- newBaseState = resultState;
- }
- }
- // Since this update will remain in the list, update the remaining
- // expiration time.
- if (newExpirationTime < _updateExpirationTime) {
- newExpirationTime = _updateExpirationTime;
- }
- } else {
- // This update does have sufficient priority. Process it and compute
- // a new result.
- resultState = getStateFromUpdate(
- workInProgress,
- queue,
- update,
- resultState,
- props,
- instance
- );
- var _callback2 = update.callback;
- if (_callback2 !== null) {
- workInProgress.effectTag |= Callback;
- // Set this to null, in case it was mutated during an aborted render.
- update.nextEffect = null;
- if (queue.lastCapturedEffect === null) {
- queue.firstCapturedEffect = queue.lastCapturedEffect = update;
- } else {
- queue.lastCapturedEffect.nextEffect = update;
- queue.lastCapturedEffect = update;
- }
- }
- }
- update = update.next;
- }
-
- if (newFirstUpdate === null) {
- queue.lastUpdate = null;
- }
- if (newFirstCapturedUpdate === null) {
- queue.lastCapturedUpdate = null;
- } else {
- workInProgress.effectTag |= Callback;
- }
- if (newFirstUpdate === null && newFirstCapturedUpdate === null) {
- // We processed every update, without skipping. That means the new base
- // state is the same as the result state.
- newBaseState = resultState;
- }
-
- queue.baseState = newBaseState;
- queue.firstUpdate = newFirstUpdate;
- queue.firstCapturedUpdate = newFirstCapturedUpdate;
-
- // Set the remaining expiration time to be whatever is remaining in the queue.
- // This should be fine because the only two other things that contribute to
- // expiration time are props and context. We're already in the middle of the
- // begin phase by the time we start processing the queue, so we've already
- // dealt with the props. Context in components that specify
- // shouldComponentUpdate is tricky; but we'll have to account for
- // that regardless.
- workInProgress.expirationTime = newExpirationTime;
- workInProgress.memoizedState = resultState;
-
- {
- currentlyProcessingQueue = null;
- }
-}
-
-function callCallback(callback, context) {
- invariant(
- typeof callback === "function",
- "Invalid argument passed as callback. Expected a function. Instead " +
- "received: %s",
- callback
- );
- callback.call(context);
-}
-
-function resetHasForceUpdateBeforeProcessing() {
- hasForceUpdate = false;
-}
-
-function checkHasForceUpdateAfterProcessing() {
- return hasForceUpdate;
-}
-
-function commitUpdateQueue(
- finishedWork,
- finishedQueue,
- instance,
- renderExpirationTime
-) {
- // If the finished render included captured updates, and there are still
- // lower priority updates left over, we need to keep the captured updates
- // in the queue so that they are rebased and not dropped once we process the
- // queue again at the lower priority.
- if (finishedQueue.firstCapturedUpdate !== null) {
- // Join the captured update list to the end of the normal list.
- if (finishedQueue.lastUpdate !== null) {
- finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate;
- finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate;
- }
- // Clear the list of captured updates.
- finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null;
- }
-
- // Commit the effects
- commitUpdateEffects(finishedQueue.firstEffect, instance);
- finishedQueue.firstEffect = finishedQueue.lastEffect = null;
-
- commitUpdateEffects(finishedQueue.firstCapturedEffect, instance);
- finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null;
-}
-
-function commitUpdateEffects(effect, instance) {
- while (effect !== null) {
- var _callback3 = effect.callback;
- if (_callback3 !== null) {
- effect.callback = null;
- callCallback(_callback3, instance);
- }
- effect = effect.nextEffect;
- }
-}
-
-function createCapturedValue(value, source) {
- // If the value is an error, call this function immediately after it is thrown
- // so the stack is accurate.
- return {
- value: value,
- source: source,
- stack: getStackByFiberInDevAndProd(source)
- };
-}
-
/**
* Similar to invariant but only logs a warning if the condition is not met.
* This can be used to log issues in development environments in critical
@@ -7177,1046 +6665,18 @@
var warning$1 = warning;
-var valueCursor = createCursor(null);
-
-var rendererSigil = void 0;
-{
- // Use this to detect multiple renderers using the same context
- rendererSigil = {};
-}
-
-var currentlyRenderingFiber = null;
-var lastContextDependency = null;
-var lastContextWithAllBitsObserved = null;
-
-function resetContextDependences() {
- // This is called right before React yields execution, to ensure `readContext`
- // cannot be called outside the render phase.
- currentlyRenderingFiber = null;
- lastContextDependency = null;
- lastContextWithAllBitsObserved = null;
-}
-
-function pushProvider(providerFiber, nextValue) {
- var context = providerFiber.type._context;
-
- if (isPrimaryRenderer) {
- push(valueCursor, context._currentValue, providerFiber);
-
- context._currentValue = nextValue;
- {
- !(
- context._currentRenderer === undefined ||
- context._currentRenderer === null ||
- context._currentRenderer === rendererSigil
- )
- ? warningWithoutStack$1(
- false,
- "Detected multiple renderers concurrently rendering the " +
- "same context provider. This is currently unsupported."
- )
- : void 0;
- context._currentRenderer = rendererSigil;
- }
- } else {
- push(valueCursor, context._currentValue2, providerFiber);
-
- context._currentValue2 = nextValue;
- {
- !(
- context._currentRenderer2 === undefined ||
- context._currentRenderer2 === null ||
- context._currentRenderer2 === rendererSigil
- )
- ? warningWithoutStack$1(
- false,
- "Detected multiple renderers concurrently rendering the " +
- "same context provider. This is currently unsupported."
- )
- : void 0;
- context._currentRenderer2 = rendererSigil;
- }
- }
-}
-
-function popProvider(providerFiber) {
- var currentValue = valueCursor.current;
-
- pop(valueCursor, providerFiber);
-
- var context = providerFiber.type._context;
- if (isPrimaryRenderer) {
- context._currentValue = currentValue;
- } else {
- context._currentValue2 = currentValue;
- }
-}
-
-function calculateChangedBits(context, newValue, oldValue) {
- // Use Object.is to compare the new context value to the old value. Inlined
- // Object.is polyfill.
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
- if (
- (oldValue === newValue &&
- (oldValue !== 0 || 1 / oldValue === 1 / newValue)) ||
- (oldValue !== oldValue && newValue !== newValue) // eslint-disable-line no-self-compare
- ) {
- // No change
- return 0;
- } else {
- var changedBits =
- typeof context._calculateChangedBits === "function"
- ? context._calculateChangedBits(oldValue, newValue)
- : maxSigned31BitInt;
-
- {
- !((changedBits & maxSigned31BitInt) === changedBits)
- ? warning$1(
- false,
- "calculateChangedBits: Expected the return value to be a " +
- "31-bit integer. Instead received: %s",
- changedBits
- )
- : void 0;
- }
- return changedBits | 0;
- }
-}
-
-function propagateContextChange(
- workInProgress,
- context,
- changedBits,
- renderExpirationTime
-) {
- var fiber = workInProgress.child;
- if (fiber !== null) {
- // Set the return pointer of the child to the work-in-progress fiber.
- fiber.return = workInProgress;
- }
- while (fiber !== null) {
- var nextFiber = void 0;
-
- // Visit this fiber.
- var dependency = fiber.firstContextDependency;
- if (dependency !== null) {
- do {
- // Check if the context matches.
- if (
- dependency.context === context &&
- (dependency.observedBits & changedBits) !== 0
- ) {
- // Match! Schedule an update on this fiber.
-
- if (fiber.tag === ClassComponent) {
- // Schedule a force update on the work-in-progress.
- var update = createUpdate(renderExpirationTime);
- update.tag = ForceUpdate;
- // TODO: Because we don't have a work-in-progress, this will add the
- // update to the current fiber, too, which means it will persist even if
- // this render is thrown away. Since it's a race condition, not sure it's
- // worth fixing.
- enqueueUpdate(fiber, update);
- }
-
- if (fiber.expirationTime < renderExpirationTime) {
- fiber.expirationTime = renderExpirationTime;
- }
- var alternate = fiber.alternate;
- if (
- alternate !== null &&
- alternate.expirationTime < renderExpirationTime
- ) {
- alternate.expirationTime = renderExpirationTime;
- }
- // Update the child expiration time of all the ancestors, including
- // the alternates.
- var node = fiber.return;
- while (node !== null) {
- alternate = node.alternate;
- if (node.childExpirationTime < renderExpirationTime) {
- node.childExpirationTime = renderExpirationTime;
- if (
- alternate !== null &&
- alternate.childExpirationTime < renderExpirationTime
- ) {
- alternate.childExpirationTime = renderExpirationTime;
- }
- } else if (
- alternate !== null &&
- alternate.childExpirationTime < renderExpirationTime
- ) {
- alternate.childExpirationTime = renderExpirationTime;
- } else {
- // Neither alternate was updated, which means the rest of the
- // ancestor path already has sufficient priority.
- break;
- }
- node = node.return;
- }
- }
- nextFiber = fiber.child;
- dependency = dependency.next;
- } while (dependency !== null);
- } else if (fiber.tag === ContextProvider) {
- // Don't scan deeper if this is a matching provider
- nextFiber = fiber.type === workInProgress.type ? null : fiber.child;
- } else {
- // Traverse down.
- nextFiber = fiber.child;
- }
-
- if (nextFiber !== null) {
- // Set the return pointer of the child to the work-in-progress fiber.
- nextFiber.return = fiber;
- } else {
- // No child. Traverse to next sibling.
- nextFiber = fiber;
- while (nextFiber !== null) {
- if (nextFiber === workInProgress) {
- // We're back to the root of this subtree. Exit.
- nextFiber = null;
- break;
- }
- var sibling = nextFiber.sibling;
- if (sibling !== null) {
- // Set the return pointer of the sibling to the work-in-progress fiber.
- sibling.return = nextFiber.return;
- nextFiber = sibling;
- break;
- }
- // No more siblings. Traverse up.
- nextFiber = nextFiber.return;
- }
- }
- fiber = nextFiber;
- }
-}
-
-function prepareToReadContext(workInProgress, renderExpirationTime) {
- currentlyRenderingFiber = workInProgress;
- lastContextDependency = null;
- lastContextWithAllBitsObserved = null;
-
- // Reset the work-in-progress list
- workInProgress.firstContextDependency = null;
-}
-
-function readContext(context, observedBits) {
- if (lastContextWithAllBitsObserved === context) {
- // Nothing to do. We already observe everything in this context.
- } else if (observedBits === false || observedBits === 0) {
- // Do not observe any updates.
- } else {
- var resolvedObservedBits = void 0; // Avoid deopting on observable arguments or heterogeneous types.
- if (
- typeof observedBits !== "number" ||
- observedBits === maxSigned31BitInt
- ) {
- // Observe all updates.
- lastContextWithAllBitsObserved = context;
- resolvedObservedBits = maxSigned31BitInt;
- } else {
- resolvedObservedBits = observedBits;
- }
-
- var contextItem = {
- context: context,
- observedBits: resolvedObservedBits,
- next: null
- };
-
- if (lastContextDependency === null) {
- invariant(
- currentlyRenderingFiber !== null,
- "Context can only be read while React is " +
- "rendering, e.g. inside the render method or getDerivedStateFromProps."
- );
- // This is the first dependency in the list
- currentlyRenderingFiber.firstContextDependency = lastContextDependency = contextItem;
- } else {
- // Append a new context item.
- lastContextDependency = lastContextDependency.next = contextItem;
- }
- }
- return isPrimaryRenderer ? context._currentValue : context._currentValue2;
-}
-
-var NoEffect$1 = /* */ 0;
-var UnmountSnapshot = /* */ 2;
-var UnmountMutation = /* */ 4;
-var MountMutation = /* */ 8;
-var UnmountLayout = /* */ 16;
-var MountLayout = /* */ 32;
-var MountPassive = /* */ 64;
-var UnmountPassive = /* */ 128;
-
-function areHookInputsEqual(arr1, arr2) {
- // Don't bother comparing lengths in prod because these arrays should be
- // passed inline.
- {
- !(arr1.length === arr2.length)
- ? warning$1(
- false,
- "Detected a variable number of hook dependencies. The length of the " +
- "dependencies array should be constant between renders.\n\n" +
- "Previous: %s\n" +
- "Incoming: %s",
- arr1.join(", "),
- arr2.join(", ")
- )
- : void 0;
- }
- for (var i = 0; i < arr1.length; i++) {
- // Inlined Object.is polyfill.
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
- var val1 = arr1[i];
- var val2 = arr2[i];
- if (
- (val1 === val2 && (val1 !== 0 || 1 / val1 === 1 / val2)) ||
- (val1 !== val1 && val2 !== val2) // eslint-disable-line no-self-compare
- ) {
- continue;
- }
- return false;
- }
- return true;
-}
-
-// These are set right before calling the component.
-var renderExpirationTime = NoWork;
-// The work-in-progress fiber. I've named it differently to distinguish it from
-// the work-in-progress hook.
-var currentlyRenderingFiber$1 = null;
-
-// Hooks are stored as a linked list on the fiber's memoizedState field. The
-// current hook list is the list that belongs to the current fiber. The
-// work-in-progress hook list is a new list that will be added to the
-// work-in-progress fiber.
-var firstCurrentHook = null;
-var currentHook = null;
-var firstWorkInProgressHook = null;
-var workInProgressHook = null;
-
-var remainingExpirationTime = NoWork;
-var componentUpdateQueue = null;
-
-// Updates scheduled during render will trigger an immediate re-render at the
-// end of the current pass. We can't store these updates on the normal queue,
-// because if the work is aborted, they should be discarded. Because this is
-// a relatively rare case, we also don't want to add an additional field to
-// either the hook or queue object types. So we store them in a lazily create
-// map of queue -> render-phase updates, which are discarded once the component
-// completes without re-rendering.
-
-// Whether the work-in-progress hook is a re-rendered hook
-var isReRender = false;
-// Whether an update was scheduled during the currently executing render pass.
-var didScheduleRenderPhaseUpdate = false;
-// Lazily created map of render-phase updates
-var renderPhaseUpdates = null;
-// Counter to prevent infinite loops.
-var numberOfReRenders = 0;
-var RE_RENDER_LIMIT = 25;
-
-function resolveCurrentlyRenderingFiber() {
- invariant(
- currentlyRenderingFiber$1 !== null,
- "Hooks can only be called inside the body of a function component."
- );
- return currentlyRenderingFiber$1;
-}
-
-function prepareToUseHooks(current, workInProgress, nextRenderExpirationTime) {
- if (!enableHooks) {
- return;
- }
- renderExpirationTime = nextRenderExpirationTime;
- currentlyRenderingFiber$1 = workInProgress;
- firstCurrentHook = current !== null ? current.memoizedState : null;
-
- // The following should have already been reset
- // currentHook = null;
- // workInProgressHook = null;
-
- // remainingExpirationTime = NoWork;
- // componentUpdateQueue = null;
-
- // isReRender = false;
- // didScheduleRenderPhaseUpdate = false;
- // renderPhaseUpdates = null;
- // numberOfReRenders = 0;
-}
-
-function finishHooks(Component, props, children, refOrContext) {
- if (!enableHooks) {
- return children;
- }
-
- // This must be called after every function component to prevent hooks from
- // being used in classes.
-
- while (didScheduleRenderPhaseUpdate) {
- // Updates were scheduled during the render phase. They are stored in
- // the `renderPhaseUpdates` map. Call the component again, reusing the
- // work-in-progress hooks and applying the additional updates on top. Keep
- // restarting until no more updates are scheduled.
- didScheduleRenderPhaseUpdate = false;
- numberOfReRenders += 1;
-
- // Start over from the beginning of the list
- currentHook = null;
- workInProgressHook = null;
- componentUpdateQueue = null;
-
- children = Component(props, refOrContext);
- }
- renderPhaseUpdates = null;
- numberOfReRenders = 0;
-
- var renderedWork = currentlyRenderingFiber$1;
-
- renderedWork.memoizedState = firstWorkInProgressHook;
- renderedWork.expirationTime = remainingExpirationTime;
- renderedWork.updateQueue = componentUpdateQueue;
-
- var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null;
-
- renderExpirationTime = NoWork;
- currentlyRenderingFiber$1 = null;
-
- firstCurrentHook = null;
- currentHook = null;
- firstWorkInProgressHook = null;
- workInProgressHook = null;
-
- remainingExpirationTime = NoWork;
- componentUpdateQueue = null;
-
- // Always set during createWorkInProgress
- // isReRender = false;
-
- // These were reset above
- // didScheduleRenderPhaseUpdate = false;
- // renderPhaseUpdates = null;
- // numberOfReRenders = 0;
-
- invariant(
- !didRenderTooFewHooks,
- "Rendered fewer hooks than expected. This may be caused by an accidental " +
- "early return statement."
- );
-
- return children;
-}
-
-function resetHooks() {
- if (!enableHooks) {
- return;
- }
-
- // This is called instead of `finishHooks` if the component throws. It's also
- // called inside mountIndeterminateComponent if we determine the component
- // is a module-style component.
- renderExpirationTime = NoWork;
- currentlyRenderingFiber$1 = null;
-
- firstCurrentHook = null;
- currentHook = null;
- firstWorkInProgressHook = null;
- workInProgressHook = null;
-
- remainingExpirationTime = NoWork;
- componentUpdateQueue = null;
-
- // Always set during createWorkInProgress
- // isReRender = false;
-
- didScheduleRenderPhaseUpdate = false;
- renderPhaseUpdates = null;
- numberOfReRenders = 0;
-}
-
-function createHook() {
- return {
- memoizedState: null,
-
- baseState: null,
- queue: null,
- baseUpdate: null,
-
- next: null
- };
-}
-
-function cloneHook(hook) {
- return {
- memoizedState: hook.memoizedState,
-
- baseState: hook.baseState,
- queue: hook.queue,
- baseUpdate: hook.baseUpdate,
-
- next: null
- };
-}
-
-function createWorkInProgressHook() {
- if (workInProgressHook === null) {
- // This is the first hook in the list
- if (firstWorkInProgressHook === null) {
- isReRender = false;
- currentHook = firstCurrentHook;
- if (currentHook === null) {
- // This is a newly mounted hook
- workInProgressHook = createHook();
- } else {
- // Clone the current hook.
- workInProgressHook = cloneHook(currentHook);
- }
- firstWorkInProgressHook = workInProgressHook;
- } else {
- // There's already a work-in-progress. Reuse it.
- isReRender = true;
- currentHook = firstCurrentHook;
- workInProgressHook = firstWorkInProgressHook;
- }
- } else {
- if (workInProgressHook.next === null) {
- isReRender = false;
- var hook = void 0;
- if (currentHook === null) {
- // This is a newly mounted hook
- hook = createHook();
- } else {
- currentHook = currentHook.next;
- if (currentHook === null) {
- // This is a newly mounted hook
- hook = createHook();
- } else {
- // Clone the current hook.
- hook = cloneHook(currentHook);
- }
- }
- // Append to the end of the list
- workInProgressHook = workInProgressHook.next = hook;
- } else {
- // There's already a work-in-progress. Reuse it.
- isReRender = true;
- workInProgressHook = workInProgressHook.next;
- currentHook = currentHook !== null ? currentHook.next : null;
- }
- }
- return workInProgressHook;
-}
-
-function createFunctionComponentUpdateQueue() {
- return {
- lastEffect: null
- };
-}
-
-function basicStateReducer(state, action) {
- return typeof action === "function" ? action(state) : action;
-}
-
-function useContext(context, observedBits) {
- // Ensure we're in a function component (class components support only the
- // .unstable_read() form)
- resolveCurrentlyRenderingFiber();
- return readContext(context, observedBits);
-}
-
-function useState(initialState) {
- return useReducer(
- basicStateReducer,
- // useReducer has a special case to support lazy useState initializers
- initialState
- );
-}
-
-function useReducer(reducer, initialState, initialAction) {
- currentlyRenderingFiber$1 = resolveCurrentlyRenderingFiber();
- workInProgressHook = createWorkInProgressHook();
- var queue = workInProgressHook.queue;
- if (queue !== null) {
- // Already have a queue, so this is an update.
- if (isReRender) {
- // This is a re-render. Apply the new render phase updates to the previous
- var _dispatch2 = queue.dispatch;
- if (renderPhaseUpdates !== null) {
- // Render phase updates are stored in a map of queue -> linked list
- var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
- if (firstRenderPhaseUpdate !== undefined) {
- renderPhaseUpdates.delete(queue);
- var newState = workInProgressHook.memoizedState;
- var update = firstRenderPhaseUpdate;
- do {
- // Process this render phase update. We don't have to check the
- // priority because it will always be the same as the current
- // render's.
- var _action = update.action;
- newState = reducer(newState, _action);
- update = update.next;
- } while (update !== null);
-
- workInProgressHook.memoizedState = newState;
-
- // Don't persist the state accumlated from the render phase updates to
- // the base state unless the queue is empty.
- // TODO: Not sure if this is the desired semantics, but it's what we
- // do for gDSFP. I can't remember why.
- if (workInProgressHook.baseUpdate === queue.last) {
- workInProgressHook.baseState = newState;
- }
-
- return [newState, _dispatch2];
- }
- }
- return [workInProgressHook.memoizedState, _dispatch2];
- }
-
- // The last update in the entire queue
- var _last = queue.last;
- // The last update that is part of the base state.
- var _baseUpdate = workInProgressHook.baseUpdate;
-
- // Find the first unprocessed update.
- var first = void 0;
- if (_baseUpdate !== null) {
- if (_last !== null) {
- // For the first update, the queue is a circular linked list where
- // `queue.last.next = queue.first`. Once the first update commits, and
- // the `baseUpdate` is no longer empty, we can unravel the list.
- _last.next = null;
- }
- first = _baseUpdate.next;
- } else {
- first = _last !== null ? _last.next : null;
- }
- if (first !== null) {
- var _newState = workInProgressHook.baseState;
- var newBaseState = null;
- var newBaseUpdate = null;
- var prevUpdate = _baseUpdate;
- var _update = first;
- var didSkip = false;
- do {
- var updateExpirationTime = _update.expirationTime;
- if (updateExpirationTime < renderExpirationTime) {
- // Priority is insufficient. Skip this update. If this is the first
- // skipped update, the previous update/state is the new base
- // update/state.
- if (!didSkip) {
- didSkip = true;
- newBaseUpdate = prevUpdate;
- newBaseState = _newState;
- }
- // Update the remaining priority in the queue.
- if (updateExpirationTime > remainingExpirationTime) {
- remainingExpirationTime = updateExpirationTime;
- }
- } else {
- // Process this update.
- var _action2 = _update.action;
- _newState = reducer(_newState, _action2);
- }
- prevUpdate = _update;
- _update = _update.next;
- } while (_update !== null && _update !== first);
-
- if (!didSkip) {
- newBaseUpdate = prevUpdate;
- newBaseState = _newState;
- }
-
- workInProgressHook.memoizedState = _newState;
- workInProgressHook.baseUpdate = newBaseUpdate;
- workInProgressHook.baseState = newBaseState;
- }
-
- var _dispatch = queue.dispatch;
- return [workInProgressHook.memoizedState, _dispatch];
- }
-
- // There's no existing queue, so this is the initial render.
- if (reducer === basicStateReducer) {
- // Special case for `useState`.
- if (typeof initialState === "function") {
- initialState = initialState();
- }
- } else if (initialAction !== undefined && initialAction !== null) {
- initialState = reducer(initialState, initialAction);
- }
- workInProgressHook.memoizedState = workInProgressHook.baseState = initialState;
- queue = workInProgressHook.queue = {
- last: null,
- dispatch: null
- };
- var dispatch = (queue.dispatch = dispatchAction.bind(
- null,
- currentlyRenderingFiber$1,
- queue
- ));
- return [workInProgressHook.memoizedState, dispatch];
-}
-
-function pushEffect(tag, create, destroy, inputs) {
- var effect = {
- tag: tag,
- create: create,
- destroy: destroy,
- inputs: inputs,
- // Circular
- next: null
- };
- if (componentUpdateQueue === null) {
- componentUpdateQueue = createFunctionComponentUpdateQueue();
- componentUpdateQueue.lastEffect = effect.next = effect;
- } else {
- var _lastEffect = componentUpdateQueue.lastEffect;
- if (_lastEffect === null) {
- componentUpdateQueue.lastEffect = effect.next = effect;
- } else {
- var firstEffect = _lastEffect.next;
- _lastEffect.next = effect;
- effect.next = firstEffect;
- componentUpdateQueue.lastEffect = effect;
- }
- }
- return effect;
-}
-
-function useRef(initialValue) {
- currentlyRenderingFiber$1 = resolveCurrentlyRenderingFiber();
- workInProgressHook = createWorkInProgressHook();
- var ref = void 0;
-
- if (workInProgressHook.memoizedState === null) {
- ref = { current: initialValue };
- {
- Object.seal(ref);
- }
- workInProgressHook.memoizedState = ref;
- } else {
- ref = workInProgressHook.memoizedState;
- }
- return ref;
-}
-
-function useLayoutEffect(create, inputs) {
- useEffectImpl(Update, UnmountMutation | MountLayout, create, inputs);
-}
-
-function useEffect(create, inputs) {
- useEffectImpl(
- Update | Passive,
- UnmountPassive | MountPassive,
- create,
- inputs
- );
-}
-
-function useEffectImpl(fiberEffectTag, hookEffectTag, create, inputs) {
- currentlyRenderingFiber$1 = resolveCurrentlyRenderingFiber();
- workInProgressHook = createWorkInProgressHook();
-
- var nextInputs = inputs !== undefined && inputs !== null ? inputs : [create];
- var destroy = null;
- if (currentHook !== null) {
- var prevEffect = currentHook.memoizedState;
- destroy = prevEffect.destroy;
- if (areHookInputsEqual(nextInputs, prevEffect.inputs)) {
- pushEffect(NoEffect$1, create, destroy, nextInputs);
- return;
- }
- }
-
- currentlyRenderingFiber$1.effectTag |= fiberEffectTag;
- workInProgressHook.memoizedState = pushEffect(
- hookEffectTag,
- create,
- destroy,
- nextInputs
- );
-}
-
-function useImperativeMethods(ref, create, inputs) {
- // TODO: If inputs are provided, should we skip comparing the ref itself?
- var nextInputs =
- inputs !== null && inputs !== undefined
- ? inputs.concat([ref])
- : [ref, create];
-
- // TODO: I've implemented this on top of useEffect because it's almost the
- // same thing, and it would require an equal amount of code. It doesn't seem
- // like a common enough use case to justify the additional size.
- useLayoutEffect(function() {
- if (typeof ref === "function") {
- var refCallback = ref;
- var _inst = create();
- refCallback(_inst);
- return function() {
- return refCallback(null);
- };
- } else if (ref !== null && ref !== undefined) {
- var refObject = ref;
- var _inst2 = create();
- refObject.current = _inst2;
- return function() {
- refObject.current = null;
- };
- }
- }, nextInputs);
-}
-
-function useCallback(callback, inputs) {
- currentlyRenderingFiber$1 = resolveCurrentlyRenderingFiber();
- workInProgressHook = createWorkInProgressHook();
-
- var nextInputs =
- inputs !== undefined && inputs !== null ? inputs : [callback];
-
- var prevState = workInProgressHook.memoizedState;
- if (prevState !== null) {
- var prevInputs = prevState[1];
- if (areHookInputsEqual(nextInputs, prevInputs)) {
- return prevState[0];
- }
- }
- workInProgressHook.memoizedState = [callback, nextInputs];
- return callback;
-}
-
-function useMemo(nextCreate, inputs) {
- currentlyRenderingFiber$1 = resolveCurrentlyRenderingFiber();
- workInProgressHook = createWorkInProgressHook();
-
- var nextInputs =
- inputs !== undefined && inputs !== null ? inputs : [nextCreate];
-
- var prevState = workInProgressHook.memoizedState;
- if (prevState !== null) {
- var prevInputs = prevState[1];
- if (areHookInputsEqual(nextInputs, prevInputs)) {
- return prevState[0];
- }
- }
-
- var nextValue = nextCreate();
- workInProgressHook.memoizedState = [nextValue, nextInputs];
- return nextValue;
-}
-
-function dispatchAction(fiber, queue, action) {
- invariant(
- numberOfReRenders < RE_RENDER_LIMIT,
- "Too many re-renders. React limits the number of renders to prevent " +
- "an infinite loop."
- );
-
- var alternate = fiber.alternate;
- if (
- fiber === currentlyRenderingFiber$1 ||
- (alternate !== null && alternate === currentlyRenderingFiber$1)
- ) {
- // This is a render phase update. Stash it in a lazily-created map of
- // queue -> linked list of updates. After this render pass, we'll restart
- // and apply the stashed updates on top of the work-in-progress hook.
- didScheduleRenderPhaseUpdate = true;
- var update = {
- expirationTime: renderExpirationTime,
- action: action,
- next: null
- };
- if (renderPhaseUpdates === null) {
- renderPhaseUpdates = new Map();
- }
- var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
- if (firstRenderPhaseUpdate === undefined) {
- renderPhaseUpdates.set(queue, update);
- } else {
- // Append the update to the end of the list.
- var lastRenderPhaseUpdate = firstRenderPhaseUpdate;
- while (lastRenderPhaseUpdate.next !== null) {
- lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
- }
- lastRenderPhaseUpdate.next = update;
- }
- } else {
- var currentTime = requestCurrentTime();
- var _expirationTime = computeExpirationForFiber(currentTime, fiber);
- var _update2 = {
- expirationTime: _expirationTime,
- action: action,
- next: null
- };
- flushPassiveEffects();
- // Append the update to the end of the list.
- var _last2 = queue.last;
- if (_last2 === null) {
- // This is the first update. Create a circular list.
- _update2.next = _update2;
- } else {
- var first = _last2.next;
- if (first !== null) {
- // Still circular.
- _update2.next = first;
- }
- _last2.next = _update2;
- }
- queue.last = _update2;
- scheduleWork(fiber, _expirationTime);
- }
-}
-
-var NO_CONTEXT = {};
-
-var contextStackCursor$1 = createCursor(NO_CONTEXT);
-var contextFiberStackCursor = createCursor(NO_CONTEXT);
-var rootInstanceStackCursor = createCursor(NO_CONTEXT);
-
-function requiredContext(c) {
- invariant(
- c !== NO_CONTEXT,
- "Expected host context to exist. This error is likely caused by a bug " +
- "in React. Please file an issue."
- );
- return c;
-}
-
-function getRootHostContainer() {
- var rootInstance = requiredContext(rootInstanceStackCursor.current);
- return rootInstance;
-}
-
-function pushHostContainer(fiber, nextRootInstance) {
- // Push current root instance onto the stack;
- // This allows us to reset root when portals are popped.
- push(rootInstanceStackCursor, nextRootInstance, fiber);
- // Track the context and the Fiber that provided it.
- // This enables us to pop only Fibers that provide unique contexts.
- push(contextFiberStackCursor, fiber, fiber);
-
- // Finally, we need to push the host context to the stack.
- // However, we can't just call getRootHostContext() and push it because
- // we'd have a different number of entries on the stack depending on
- // whether getRootHostContext() throws somewhere in renderer code or not.
- // So we push an empty value first. This lets us safely unwind on errors.
- push(contextStackCursor$1, NO_CONTEXT, fiber);
- var nextRootContext = getRootHostContext(nextRootInstance);
- // Now that we know this function doesn't throw, replace it.
- pop(contextStackCursor$1, fiber);
- push(contextStackCursor$1, nextRootContext, fiber);
-}
-
-function popHostContainer(fiber) {
- pop(contextStackCursor$1, fiber);
- pop(contextFiberStackCursor, fiber);
- pop(rootInstanceStackCursor, fiber);
-}
-
-function getHostContext() {
- var context = requiredContext(contextStackCursor$1.current);
- return context;
-}
-
-function pushHostContext(fiber) {
- var rootInstance = requiredContext(rootInstanceStackCursor.current);
- var context = requiredContext(contextStackCursor$1.current);
- var nextContext = getChildHostContext(context, fiber.type, rootInstance);
-
- // Don't push this Fiber's context unless it's unique.
- if (context === nextContext) {
- return;
- }
-
- // Track the context and the Fiber that provided it.
- // This enables us to pop only Fibers that provide unique contexts.
- push(contextFiberStackCursor, fiber, fiber);
- push(contextStackCursor$1, nextContext, fiber);
-}
-
-function popHostContext(fiber) {
- // Do not pop unless this Fiber provided the current context.
- // pushHostContext() only pushes Fibers that provide unique contexts.
- if (contextFiberStackCursor.current !== fiber) {
- return;
- }
-
- pop(contextStackCursor$1, fiber);
- pop(contextFiberStackCursor, fiber);
-}
-
-var commitTime = 0;
-var profilerStartTime = -1;
-
-function getCommitTime() {
- return commitTime;
-}
-
-function recordCommitTime() {
- if (!enableProfilerTimer) {
- return;
- }
- commitTime = now$$1();
-}
-
-function startProfilerTimer(fiber) {
- if (!enableProfilerTimer) {
- return;
- }
-
- profilerStartTime = now$$1();
-
- if (fiber.actualStartTime < 0) {
- fiber.actualStartTime = now$$1();
- }
-}
-
-function stopProfilerTimerIfRunning(fiber) {
- if (!enableProfilerTimer) {
- return;
- }
- profilerStartTime = -1;
-}
-
-function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) {
- if (!enableProfilerTimer) {
- return;
- }
-
- if (profilerStartTime >= 0) {
- var elapsedTime = now$$1() - profilerStartTime;
- fiber.actualDuration += elapsedTime;
- if (overrideBaseTime) {
- fiber.selfBaseDuration = elapsedTime;
- }
- profilerStartTime = -1;
- }
-}
-
-/*eslint-disable no-self-compare */
-
-var hasOwnProperty = Object.prototype.hasOwnProperty;
-
/**
* inlined Object.is polyfill to avoid requiring consumers ship their own
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
*/
function is(x, y) {
- // SameValue algorithm
- if (x === y) {
- // Steps 1-5, 7-10
- // Steps 6.b-6.e: +0 != -0
- // Added the nonzero y check to make Flow happy, but it is redundant
- return x !== 0 || y !== 0 || 1 / x === 1 / y;
- } else {
- // Step 6.a: NaN == NaN
- return x !== x && y !== y;
- }
+ return (
+ (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare
+ );
}
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+
/**
* Performs equality by iterating through keys on an object and returning false
* when any key has values which are not strictly equal between the arguments.
@@ -8317,19 +6777,19 @@
}
}
);
+ // Handle synchronous thenables.
+ switch (lazyComponent._status) {
+ case Resolved:
+ return lazyComponent._result;
+ case Rejected:
+ throw lazyComponent._result;
+ }
lazyComponent._result = _thenable;
throw _thenable;
}
}
}
-var ReactCurrentOwner$4 = ReactSharedInternals.ReactCurrentOwner;
-
-function readContext$1(contextType) {
- var dispatcher = ReactCurrentOwner$4.currentDispatcher;
- return dispatcher.readContext(contextType);
-}
-
var fakeInternalInstance = {};
var isArray$1 = Array.isArray;
@@ -8839,7 +7299,7 @@
}
}
- context = readContext$1(contextType);
+ context = readContext(contextType);
} else {
unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
var contextTypes = ctor.contextTypes;
@@ -9041,7 +7501,7 @@
var contextType = ctor.contextType;
if (typeof contextType === "object" && contextType !== null) {
- instance.context = readContext$1(contextType);
+ instance.context = readContext(contextType);
} else {
var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
instance.context = getMaskedContext(workInProgress, unmaskedContext);
@@ -9149,7 +7609,7 @@
var contextType = ctor.contextType;
var nextContext = void 0;
if (typeof contextType === "object" && contextType !== null) {
- nextContext = readContext$1(contextType);
+ nextContext = readContext(contextType);
} else {
var nextLegacyUnmaskedContext = getUnmaskedContext(
workInProgress,
@@ -9298,7 +7758,7 @@
var contextType = ctor.contextType;
var nextContext = void 0;
if (typeof contextType === "object" && contextType !== null) {
- nextContext = readContext$1(contextType);
+ nextContext = readContext(contextType);
} else {
var nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
nextContext = getMaskedContext(workInProgress, nextUnmaskedContext);
@@ -9488,7 +7948,7 @@
child._store.validated = true;
var currentComponentErrorInfo =
- "Each child in an array or iterator should have a unique " +
+ "Each child in a list should have a unique " +
'"key" prop. See https://fb.me/react-warning-keys for ' +
"more information." +
getCurrentFiberStackInDev();
@@ -9499,7 +7959,7 @@
warning$1(
false,
- "Each child in an array or iterator should have a unique " +
+ "Each child in a list should have a unique " +
'"key" prop. See https://fb.me/react-warning-keys for ' +
"more information."
);
@@ -9542,7 +8002,8 @@
var ownerFiber = owner;
invariant(
ownerFiber.tag === ClassComponent,
- "Function components cannot have refs."
+ "Function components cannot have refs. " +
+ "Did you mean to use React.forwardRef()?"
);
inst = ownerFiber.stateNode;
}
@@ -10106,7 +8567,7 @@
newChildren,
expirationTime
) {
- // This algorithm can't optimize by searching from boths ends since we
+ // 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.
@@ -10748,6 +9209,1387 @@
newChild.sibling = null;
}
+var NO_CONTEXT = {};
+
+var contextStackCursor$1 = createCursor(NO_CONTEXT);
+var contextFiberStackCursor = createCursor(NO_CONTEXT);
+var rootInstanceStackCursor = createCursor(NO_CONTEXT);
+
+function requiredContext(c) {
+ invariant(
+ c !== NO_CONTEXT,
+ "Expected host context to exist. This error is likely caused by a bug " +
+ "in React. Please file an issue."
+ );
+ return c;
+}
+
+function getRootHostContainer() {
+ var rootInstance = requiredContext(rootInstanceStackCursor.current);
+ return rootInstance;
+}
+
+function pushHostContainer(fiber, nextRootInstance) {
+ // Push current root instance onto the stack;
+ // This allows us to reset root when portals are popped.
+ push(rootInstanceStackCursor, nextRootInstance, fiber);
+ // Track the context and the Fiber that provided it.
+ // This enables us to pop only Fibers that provide unique contexts.
+ push(contextFiberStackCursor, fiber, fiber);
+
+ // Finally, we need to push the host context to the stack.
+ // However, we can't just call getRootHostContext() and push it because
+ // we'd have a different number of entries on the stack depending on
+ // whether getRootHostContext() throws somewhere in renderer code or not.
+ // So we push an empty value first. This lets us safely unwind on errors.
+ push(contextStackCursor$1, NO_CONTEXT, fiber);
+ var nextRootContext = getRootHostContext(nextRootInstance);
+ // Now that we know this function doesn't throw, replace it.
+ pop(contextStackCursor$1, fiber);
+ push(contextStackCursor$1, nextRootContext, fiber);
+}
+
+function popHostContainer(fiber) {
+ pop(contextStackCursor$1, fiber);
+ pop(contextFiberStackCursor, fiber);
+ pop(rootInstanceStackCursor, fiber);
+}
+
+function getHostContext() {
+ var context = requiredContext(contextStackCursor$1.current);
+ return context;
+}
+
+function pushHostContext(fiber) {
+ var rootInstance = requiredContext(rootInstanceStackCursor.current);
+ var context = requiredContext(contextStackCursor$1.current);
+ var nextContext = getChildHostContext(context, fiber.type, rootInstance);
+
+ // Don't push this Fiber's context unless it's unique.
+ if (context === nextContext) {
+ return;
+ }
+
+ // Track the context and the Fiber that provided it.
+ // This enables us to pop only Fibers that provide unique contexts.
+ push(contextFiberStackCursor, fiber, fiber);
+ push(contextStackCursor$1, nextContext, fiber);
+}
+
+function popHostContext(fiber) {
+ // Do not pop unless this Fiber provided the current context.
+ // pushHostContext() only pushes Fibers that provide unique contexts.
+ if (contextFiberStackCursor.current !== fiber) {
+ return;
+ }
+
+ pop(contextStackCursor$1, fiber);
+ pop(contextFiberStackCursor, fiber);
+}
+
+var NoEffect$1 = /* */ 0;
+var UnmountSnapshot = /* */ 2;
+var UnmountMutation = /* */ 4;
+var MountMutation = /* */ 8;
+var UnmountLayout = /* */ 16;
+var MountLayout = /* */ 32;
+var MountPassive = /* */ 64;
+var UnmountPassive = /* */ 128;
+
+var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher;
+
+var didWarnAboutMismatchedHooksForComponent = void 0;
+{
+ didWarnAboutMismatchedHooksForComponent = new Set();
+}
+
+// These are set right before calling the component.
+var renderExpirationTime = NoWork;
+// The work-in-progress fiber. I've named it differently to distinguish it from
+// the work-in-progress hook.
+var currentlyRenderingFiber$1 = null;
+
+// Hooks are stored as a linked list on the fiber's memoizedState field. The
+// current hook list is the list that belongs to the current fiber. The
+// work-in-progress hook list is a new list that will be added to the
+// work-in-progress fiber.
+var firstCurrentHook = null;
+var currentHook = null;
+var nextCurrentHook = null;
+var firstWorkInProgressHook = null;
+var workInProgressHook = null;
+var nextWorkInProgressHook = null;
+
+var remainingExpirationTime = NoWork;
+var componentUpdateQueue = null;
+var sideEffectTag = 0;
+
+// Updates scheduled during render will trigger an immediate re-render at the
+// end of the current pass. We can't store these updates on the normal queue,
+// because if the work is aborted, they should be discarded. Because this is
+// a relatively rare case, we also don't want to add an additional field to
+// either the hook or queue object types. So we store them in a lazily create
+// map of queue -> render-phase updates, which are discarded once the component
+// completes without re-rendering.
+
+// Whether an update was scheduled during the currently executing render pass.
+var didScheduleRenderPhaseUpdate = false;
+// Lazily created map of render-phase updates
+var renderPhaseUpdates = null;
+// Counter to prevent infinite loops.
+var numberOfReRenders = 0;
+var RE_RENDER_LIMIT = 25;
+
+// In DEV, this is the name of the currently executing primitive hook
+var currentHookNameInDev = null;
+
+function warnOnHookMismatchInDev() {
+ {
+ var componentName = getComponentName(currentlyRenderingFiber$1.type);
+ if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) {
+ didWarnAboutMismatchedHooksForComponent.add(componentName);
+
+ var secondColumnStart = 22;
+
+ var table = "";
+ var prevHook = firstCurrentHook;
+ var nextHook = firstWorkInProgressHook;
+ var n = 1;
+ while (prevHook !== null && nextHook !== null) {
+ var oldHookName = prevHook._debugType;
+ var newHookName = nextHook._debugType;
+
+ var row = n + ". " + oldHookName;
+
+ // Extra space so second column lines up
+ // lol @ IE not supporting String#repeat
+ while (row.length < secondColumnStart) {
+ row += " ";
+ }
+
+ row += newHookName + "\n";
+
+ table += row;
+ prevHook = prevHook.next;
+ nextHook = nextHook.next;
+ n++;
+ }
+
+ warning$1(
+ false,
+ "React has detected a change in the order of Hooks called by %s. " +
+ "This will lead to bugs and errors if not fixed. " +
+ "For more information, read the Rules of Hooks: https://fb.me/rules-of-hooks\n\n" +
+ " Previous render Next render\n" +
+ " -------------------------------\n" +
+ "%s" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
+ componentName,
+ table
+ );
+ }
+ }
+}
+
+function throwInvalidHookError() {
+ invariant(
+ false,
+ "Hooks can only be called inside the body of a function component. " +
+ "(https://fb.me/react-invalid-hook-call)"
+ );
+}
+
+function areHookInputsEqual(nextDeps, prevDeps) {
+ if (prevDeps === null) {
+ {
+ warning$1(
+ false,
+ "%s received a final argument during this render, but not during " +
+ "the previous render. Even though the final argument is optional, " +
+ "its type cannot change between renders.",
+ currentHookNameInDev
+ );
+ }
+ return false;
+ }
+
+ {
+ // Don't bother comparing lengths in prod because these arrays should be
+ // passed inline.
+ if (nextDeps.length !== prevDeps.length) {
+ warning$1(
+ false,
+ "The final argument passed to %s changed size between renders. The " +
+ "order and size of this array must remain constant.\n\n" +
+ "Previous: %s\n" +
+ "Incoming: %s",
+ currentHookNameInDev,
+ "[" + nextDeps.join(", ") + "]",
+ "[" + prevDeps.join(", ") + "]"
+ );
+ }
+ }
+ for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
+ if (is(nextDeps[i], prevDeps[i])) {
+ continue;
+ }
+ return false;
+ }
+ return true;
+}
+
+function renderWithHooks(
+ current,
+ workInProgress,
+ Component,
+ props,
+ refOrContext,
+ nextRenderExpirationTime
+) {
+ renderExpirationTime = nextRenderExpirationTime;
+ currentlyRenderingFiber$1 = workInProgress;
+ firstCurrentHook = nextCurrentHook =
+ current !== null ? current.memoizedState : null;
+
+ // The following should have already been reset
+ // currentHook = null;
+ // workInProgressHook = null;
+
+ // remainingExpirationTime = NoWork;
+ // componentUpdateQueue = null;
+
+ // didScheduleRenderPhaseUpdate = false;
+ // renderPhaseUpdates = null;
+ // numberOfReRenders = 0;
+ // sideEffectTag = 0;
+
+ {
+ ReactCurrentDispatcher$1.current =
+ nextCurrentHook === null
+ ? HooksDispatcherOnMountInDEV
+ : HooksDispatcherOnUpdateInDEV;
+ }
+
+ var children = Component(props, refOrContext);
+
+ if (didScheduleRenderPhaseUpdate) {
+ do {
+ didScheduleRenderPhaseUpdate = false;
+ numberOfReRenders += 1;
+
+ // Start over from the beginning of the list
+ firstCurrentHook = nextCurrentHook =
+ current !== null ? current.memoizedState : null;
+ nextWorkInProgressHook = firstWorkInProgressHook;
+
+ currentHook = null;
+ workInProgressHook = null;
+ componentUpdateQueue = null;
+
+ ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdateInDEV;
+
+ children = Component(props, refOrContext);
+ } while (didScheduleRenderPhaseUpdate);
+
+ renderPhaseUpdates = null;
+ numberOfReRenders = 0;
+ }
+
+ {
+ currentHookNameInDev = null;
+ }
+
+ // We can assume the previous dispatcher is always this one, since we set it
+ // at the beginning of the render phase and there's no re-entrancy.
+ ReactCurrentDispatcher$1.current = ContextOnlyDispatcher;
+
+ var renderedWork = currentlyRenderingFiber$1;
+
+ renderedWork.memoizedState = firstWorkInProgressHook;
+ renderedWork.expirationTime = remainingExpirationTime;
+ renderedWork.updateQueue = componentUpdateQueue;
+ renderedWork.effectTag |= sideEffectTag;
+
+ var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null;
+
+ renderExpirationTime = NoWork;
+ currentlyRenderingFiber$1 = null;
+
+ firstCurrentHook = null;
+ currentHook = null;
+ nextCurrentHook = null;
+ firstWorkInProgressHook = null;
+ workInProgressHook = null;
+ nextWorkInProgressHook = null;
+
+ remainingExpirationTime = NoWork;
+ componentUpdateQueue = null;
+ sideEffectTag = 0;
+
+ // These were reset above
+ // didScheduleRenderPhaseUpdate = false;
+ // renderPhaseUpdates = null;
+ // numberOfReRenders = 0;
+
+ invariant(
+ !didRenderTooFewHooks,
+ "Rendered fewer hooks than expected. This may be caused by an accidental " +
+ "early return statement."
+ );
+
+ return children;
+}
+
+function bailoutHooks(current, workInProgress, expirationTime) {
+ workInProgress.updateQueue = current.updateQueue;
+ workInProgress.effectTag &= ~(Passive | Update);
+ if (current.expirationTime <= expirationTime) {
+ current.expirationTime = NoWork;
+ }
+}
+
+function resetHooks() {
+ // We can assume the previous dispatcher is always this one, since we set it
+ // at the beginning of the render phase and there's no re-entrancy.
+ ReactCurrentDispatcher$1.current = ContextOnlyDispatcher;
+
+ // This is used to reset the state of this module when a component throws.
+ // It's also called inside mountIndeterminateComponent if we determine the
+ // component is a module-style component.
+ renderExpirationTime = NoWork;
+ currentlyRenderingFiber$1 = null;
+
+ firstCurrentHook = null;
+ currentHook = null;
+ nextCurrentHook = null;
+ firstWorkInProgressHook = null;
+ workInProgressHook = null;
+ nextWorkInProgressHook = null;
+
+ remainingExpirationTime = NoWork;
+ componentUpdateQueue = null;
+ sideEffectTag = 0;
+
+ {
+ currentHookNameInDev = null;
+ }
+
+ didScheduleRenderPhaseUpdate = false;
+ renderPhaseUpdates = null;
+ numberOfReRenders = 0;
+}
+
+function mountWorkInProgressHook() {
+ var hook = {
+ memoizedState: null,
+
+ baseState: null,
+ queue: null,
+ baseUpdate: null,
+
+ next: null
+ };
+
+ {
+ hook._debugType = currentHookNameInDev;
+ }
+ if (workInProgressHook === null) {
+ // This is the first hook in the list
+ firstWorkInProgressHook = workInProgressHook = hook;
+ } else {
+ // Append to the end of the list
+ workInProgressHook = workInProgressHook.next = hook;
+ }
+ return workInProgressHook;
+}
+
+function updateWorkInProgressHook() {
+ // This function is used both for updates and for re-renders triggered by a
+ // render phase update. It assumes there is either a current hook we can
+ // clone, or a work-in-progress hook from a previous render pass that we can
+ // use as a base. When we reach the end of the base list, we must switch to
+ // the dispatcher used for mounts.
+ if (nextWorkInProgressHook !== null) {
+ // There's already a work-in-progress. Reuse it.
+ workInProgressHook = nextWorkInProgressHook;
+ nextWorkInProgressHook = workInProgressHook.next;
+
+ currentHook = nextCurrentHook;
+ nextCurrentHook = currentHook !== null ? currentHook.next : null;
+ } else {
+ // Clone from the current hook.
+ invariant(
+ nextCurrentHook !== null,
+ "Rendered more hooks than during the previous render."
+ );
+ currentHook = nextCurrentHook;
+
+ var newHook = {
+ memoizedState: currentHook.memoizedState,
+
+ baseState: currentHook.baseState,
+ queue: currentHook.queue,
+ baseUpdate: currentHook.baseUpdate,
+
+ next: null
+ };
+
+ if (workInProgressHook === null) {
+ // This is the first hook in the list.
+ workInProgressHook = firstWorkInProgressHook = newHook;
+ } else {
+ // Append to the end of the list.
+ workInProgressHook = workInProgressHook.next = newHook;
+ }
+ nextCurrentHook = currentHook.next;
+
+ {
+ newHook._debugType = currentHookNameInDev;
+ if (currentHookNameInDev !== currentHook._debugType) {
+ warnOnHookMismatchInDev();
+ }
+ }
+ }
+ return workInProgressHook;
+}
+
+function createFunctionComponentUpdateQueue() {
+ return {
+ lastEffect: null
+ };
+}
+
+function basicStateReducer(state, action) {
+ return typeof action === "function" ? action(state) : action;
+}
+
+function mountContext(context, observedBits) {
+ {
+ mountWorkInProgressHook();
+ }
+ return readContext(context, observedBits);
+}
+
+function updateContext(context, observedBits) {
+ {
+ updateWorkInProgressHook();
+ }
+ return readContext(context, observedBits);
+}
+
+function mountReducer(reducer, initialArg, init) {
+ var hook = mountWorkInProgressHook();
+ var initialState = void 0;
+ if (init !== undefined) {
+ initialState = init(initialArg);
+ } else {
+ initialState = initialArg;
+ }
+ hook.memoizedState = hook.baseState = initialState;
+ var queue = (hook.queue = {
+ last: null,
+ dispatch: null,
+ eagerReducer: reducer,
+ eagerState: initialState
+ });
+ var dispatch = (queue.dispatch = dispatchAction.bind(
+ null,
+ // Flow doesn't know this is non-null, but we do.
+ currentlyRenderingFiber$1,
+ queue
+ ));
+ return [hook.memoizedState, dispatch];
+}
+
+function updateReducer(reducer, initialArg, init) {
+ var hook = updateWorkInProgressHook();
+ var queue = hook.queue;
+ invariant(
+ queue !== null,
+ "Should have a queue. This is likely a bug in React. Please file an issue."
+ );
+
+ if (numberOfReRenders > 0) {
+ // This is a re-render. Apply the new render phase updates to the previous
+ var _dispatch = queue.dispatch;
+ if (renderPhaseUpdates !== null) {
+ // Render phase updates are stored in a map of queue -> linked list
+ var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+ if (firstRenderPhaseUpdate !== undefined) {
+ renderPhaseUpdates.delete(queue);
+ var newState = hook.memoizedState;
+ var update = firstRenderPhaseUpdate;
+ do {
+ // Process this render phase update. We don't have to check the
+ // priority because it will always be the same as the current
+ // render's.
+ var _action = update.action;
+ newState = reducer(newState, _action);
+ update = update.next;
+ } while (update !== null);
+
+ // Mark that the fiber performed work, but only if the new state is
+ // different from the current state.
+ if (!is(newState, hook.memoizedState)) {
+ markWorkInProgressReceivedUpdate();
+ }
+
+ hook.memoizedState = newState;
+ // Don't persist the state accumlated from the render phase updates to
+ // the base state unless the queue is empty.
+ // TODO: Not sure if this is the desired semantics, but it's what we
+ // do for gDSFP. I can't remember why.
+ if (hook.baseUpdate === queue.last) {
+ hook.baseState = newState;
+ }
+
+ queue.eagerReducer = reducer;
+ queue.eagerState = newState;
+
+ return [newState, _dispatch];
+ }
+ }
+ return [hook.memoizedState, _dispatch];
+ }
+
+ // The last update in the entire queue
+ var last = queue.last;
+ // The last update that is part of the base state.
+ var baseUpdate = hook.baseUpdate;
+ var baseState = hook.baseState;
+
+ // Find the first unprocessed update.
+ var first = void 0;
+ if (baseUpdate !== null) {
+ if (last !== null) {
+ // For the first update, the queue is a circular linked list where
+ // `queue.last.next = queue.first`. Once the first update commits, and
+ // the `baseUpdate` is no longer empty, we can unravel the list.
+ last.next = null;
+ }
+ first = baseUpdate.next;
+ } else {
+ first = last !== null ? last.next : null;
+ }
+ if (first !== null) {
+ var _newState = baseState;
+ var newBaseState = null;
+ var newBaseUpdate = null;
+ var prevUpdate = baseUpdate;
+ var _update = first;
+ var didSkip = false;
+ do {
+ var updateExpirationTime = _update.expirationTime;
+ if (updateExpirationTime < renderExpirationTime) {
+ // Priority is insufficient. Skip this update. If this is the first
+ // skipped update, the previous update/state is the new base
+ // update/state.
+ if (!didSkip) {
+ didSkip = true;
+ newBaseUpdate = prevUpdate;
+ newBaseState = _newState;
+ }
+ // Update the remaining priority in the queue.
+ if (updateExpirationTime > remainingExpirationTime) {
+ remainingExpirationTime = updateExpirationTime;
+ }
+ } else {
+ // Process this update.
+ if (_update.eagerReducer === reducer) {
+ // If this update was processed eagerly, and its reducer matches the
+ // current reducer, we can use the eagerly computed state.
+ _newState = _update.eagerState;
+ } else {
+ var _action2 = _update.action;
+ _newState = reducer(_newState, _action2);
+ }
+ }
+ prevUpdate = _update;
+ _update = _update.next;
+ } while (_update !== null && _update !== first);
+
+ if (!didSkip) {
+ newBaseUpdate = prevUpdate;
+ newBaseState = _newState;
+ }
+
+ // Mark that the fiber performed work, but only if the new state is
+ // different from the current state.
+ if (!is(_newState, hook.memoizedState)) {
+ markWorkInProgressReceivedUpdate();
+ }
+
+ hook.memoizedState = _newState;
+ hook.baseUpdate = newBaseUpdate;
+ hook.baseState = newBaseState;
+
+ queue.eagerReducer = reducer;
+ queue.eagerState = _newState;
+ }
+
+ var dispatch = queue.dispatch;
+ return [hook.memoizedState, dispatch];
+}
+
+function mountState(initialState) {
+ var hook = mountWorkInProgressHook();
+ if (typeof initialState === "function") {
+ initialState = initialState();
+ }
+ hook.memoizedState = hook.baseState = initialState;
+ var queue = (hook.queue = {
+ last: null,
+ dispatch: null,
+ eagerReducer: basicStateReducer,
+ eagerState: initialState
+ });
+ var dispatch = (queue.dispatch = dispatchAction.bind(
+ null,
+ // Flow doesn't know this is non-null, but we do.
+ currentlyRenderingFiber$1,
+ queue
+ ));
+ return [hook.memoizedState, dispatch];
+}
+
+function updateState(initialState) {
+ return updateReducer(basicStateReducer, initialState);
+}
+
+function pushEffect(tag, create, destroy, deps) {
+ var effect = {
+ tag: tag,
+ create: create,
+ destroy: destroy,
+ deps: deps,
+ // Circular
+ next: null
+ };
+ if (componentUpdateQueue === null) {
+ componentUpdateQueue = createFunctionComponentUpdateQueue();
+ componentUpdateQueue.lastEffect = effect.next = effect;
+ } else {
+ var _lastEffect = componentUpdateQueue.lastEffect;
+ if (_lastEffect === null) {
+ componentUpdateQueue.lastEffect = effect.next = effect;
+ } else {
+ var firstEffect = _lastEffect.next;
+ _lastEffect.next = effect;
+ effect.next = firstEffect;
+ componentUpdateQueue.lastEffect = effect;
+ }
+ }
+ return effect;
+}
+
+function mountRef(initialValue) {
+ var hook = mountWorkInProgressHook();
+ var ref = { current: initialValue };
+ {
+ Object.seal(ref);
+ }
+ hook.memoizedState = ref;
+ return ref;
+}
+
+function updateRef(initialValue) {
+ var hook = updateWorkInProgressHook();
+ return hook.memoizedState;
+}
+
+function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
+ var hook = mountWorkInProgressHook();
+ var nextDeps = deps === undefined ? null : deps;
+ sideEffectTag |= fiberEffectTag;
+ hook.memoizedState = pushEffect(hookEffectTag, create, undefined, nextDeps);
+}
+
+function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
+ var hook = updateWorkInProgressHook();
+ var nextDeps = deps === undefined ? null : deps;
+ var destroy = undefined;
+
+ if (currentHook !== null) {
+ var prevEffect = currentHook.memoizedState;
+ destroy = prevEffect.destroy;
+ if (nextDeps !== null) {
+ var prevDeps = prevEffect.deps;
+ if (areHookInputsEqual(nextDeps, prevDeps)) {
+ pushEffect(NoEffect$1, create, destroy, nextDeps);
+ return;
+ }
+ }
+ }
+
+ sideEffectTag |= fiberEffectTag;
+ hook.memoizedState = pushEffect(hookEffectTag, create, destroy, nextDeps);
+}
+
+function mountEffect(create, deps) {
+ return mountEffectImpl(
+ Update | Passive,
+ UnmountPassive | MountPassive,
+ create,
+ deps
+ );
+}
+
+function updateEffect(create, deps) {
+ return updateEffectImpl(
+ Update | Passive,
+ UnmountPassive | MountPassive,
+ create,
+ deps
+ );
+}
+
+function mountLayoutEffect(create, deps) {
+ return mountEffectImpl(Update, UnmountMutation | MountLayout, create, deps);
+}
+
+function updateLayoutEffect(create, deps) {
+ return updateEffectImpl(Update, UnmountMutation | MountLayout, create, deps);
+}
+
+function imperativeHandleEffect(create, ref) {
+ if (typeof ref === "function") {
+ var refCallback = ref;
+ var _inst = create();
+ refCallback(_inst);
+ return function() {
+ refCallback(null);
+ };
+ } else if (ref !== null && ref !== undefined) {
+ var refObject = ref;
+ {
+ !refObject.hasOwnProperty("current")
+ ? warning$1(
+ false,
+ "Expected useImperativeHandle() first argument to either be a " +
+ "ref callback or React.createRef() object. Instead received: %s.",
+ "an object with keys {" + Object.keys(refObject).join(", ") + "}"
+ )
+ : void 0;
+ }
+ var _inst2 = create();
+ refObject.current = _inst2;
+ return function() {
+ refObject.current = null;
+ };
+ }
+}
+
+function mountImperativeHandle(ref, create, deps) {
+ {
+ !(typeof create === "function")
+ ? warning$1(
+ false,
+ "Expected useImperativeHandle() second argument to be a function " +
+ "that creates a handle. Instead received: %s.",
+ create !== null ? typeof create : "null"
+ )
+ : void 0;
+ }
+
+ // TODO: If deps are provided, should we skip comparing the ref itself?
+ var effectDeps =
+ deps !== null && deps !== undefined ? deps.concat([ref]) : null;
+
+ return mountEffectImpl(
+ Update,
+ UnmountMutation | MountLayout,
+ imperativeHandleEffect.bind(null, create, ref),
+ effectDeps
+ );
+}
+
+function updateImperativeHandle(ref, create, deps) {
+ {
+ !(typeof create === "function")
+ ? warning$1(
+ false,
+ "Expected useImperativeHandle() second argument to be a function " +
+ "that creates a handle. Instead received: %s.",
+ create !== null ? typeof create : "null"
+ )
+ : void 0;
+ }
+
+ // TODO: If deps are provided, should we skip comparing the ref itself?
+ var effectDeps =
+ deps !== null && deps !== undefined ? deps.concat([ref]) : null;
+
+ return updateEffectImpl(
+ Update,
+ UnmountMutation | MountLayout,
+ imperativeHandleEffect.bind(null, create, ref),
+ effectDeps
+ );
+}
+
+function mountDebugValue(value, formatterFn) {
+ // This hook is normally a no-op.
+ // The react-debug-hooks package injects its own implementation
+ // so that e.g. DevTools can display custom hook values.
+}
+
+var updateDebugValue = mountDebugValue;
+
+function mountCallback(callback, deps) {
+ var hook = mountWorkInProgressHook();
+ var nextDeps = deps === undefined ? null : deps;
+ hook.memoizedState = [callback, nextDeps];
+ return callback;
+}
+
+function updateCallback(callback, deps) {
+ var hook = updateWorkInProgressHook();
+ var nextDeps = deps === undefined ? null : deps;
+ var prevState = hook.memoizedState;
+ if (prevState !== null) {
+ if (nextDeps !== null) {
+ var prevDeps = prevState[1];
+ if (areHookInputsEqual(nextDeps, prevDeps)) {
+ return prevState[0];
+ }
+ }
+ }
+ hook.memoizedState = [callback, nextDeps];
+ return callback;
+}
+
+function mountMemo(nextCreate, deps) {
+ var hook = mountWorkInProgressHook();
+ var nextDeps = deps === undefined ? null : deps;
+ var nextValue = nextCreate();
+ hook.memoizedState = [nextValue, nextDeps];
+ return nextValue;
+}
+
+function updateMemo(nextCreate, deps) {
+ var hook = updateWorkInProgressHook();
+ var nextDeps = deps === undefined ? null : deps;
+ var prevState = hook.memoizedState;
+ if (prevState !== null) {
+ // Assume these are defined. If they're not, areHookInputsEqual will warn.
+ if (nextDeps !== null) {
+ var prevDeps = prevState[1];
+ if (areHookInputsEqual(nextDeps, prevDeps)) {
+ return prevState[0];
+ }
+ }
+ }
+ var nextValue = nextCreate();
+ hook.memoizedState = [nextValue, nextDeps];
+ return nextValue;
+}
+
+// in a test-like environment, we want to warn if dispatchAction()
+// is called outside of a batchedUpdates/TestUtils.act(...) call.
+var shouldWarnForUnbatchedSetState = false;
+
+{
+ // jest isn't a 'global', it's just exposed to tests via a wrapped function
+ // further, this isn't a test file, so flow doesn't recognize the symbol. So...
+ // $FlowExpectedError - because requirements don't give a damn about your type sigs.
+ if ("undefined" !== typeof jest) {
+ shouldWarnForUnbatchedSetState = true;
+ }
+}
+
+function dispatchAction(fiber, queue, action) {
+ invariant(
+ numberOfReRenders < RE_RENDER_LIMIT,
+ "Too many re-renders. React limits the number of renders to prevent " +
+ "an infinite loop."
+ );
+
+ {
+ !(arguments.length <= 3)
+ ? warning$1(
+ false,
+ "State updates from the useState() and useReducer() Hooks don't support the " +
+ "second callback argument. To execute a side effect after " +
+ "rendering, declare it in the component body with useEffect()."
+ )
+ : void 0;
+ }
+
+ var alternate = fiber.alternate;
+ if (
+ fiber === currentlyRenderingFiber$1 ||
+ (alternate !== null && alternate === currentlyRenderingFiber$1)
+ ) {
+ // This is a render phase update. Stash it in a lazily-created map of
+ // queue -> linked list of updates. After this render pass, we'll restart
+ // and apply the stashed updates on top of the work-in-progress hook.
+ didScheduleRenderPhaseUpdate = true;
+ var update = {
+ expirationTime: renderExpirationTime,
+ action: action,
+ eagerReducer: null,
+ eagerState: null,
+ next: null
+ };
+ if (renderPhaseUpdates === null) {
+ renderPhaseUpdates = new Map();
+ }
+ var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+ if (firstRenderPhaseUpdate === undefined) {
+ renderPhaseUpdates.set(queue, update);
+ } else {
+ // Append the update to the end of the list.
+ var lastRenderPhaseUpdate = firstRenderPhaseUpdate;
+ while (lastRenderPhaseUpdate.next !== null) {
+ lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
+ }
+ lastRenderPhaseUpdate.next = update;
+ }
+ } else {
+ flushPassiveEffects();
+
+ var currentTime = requestCurrentTime();
+ var _expirationTime = computeExpirationForFiber(currentTime, fiber);
+
+ var _update2 = {
+ expirationTime: _expirationTime,
+ action: action,
+ eagerReducer: null,
+ eagerState: null,
+ next: null
+ };
+
+ // Append the update to the end of the list.
+ var _last = queue.last;
+ if (_last === null) {
+ // This is the first update. Create a circular list.
+ _update2.next = _update2;
+ } else {
+ var first = _last.next;
+ if (first !== null) {
+ // Still circular.
+ _update2.next = first;
+ }
+ _last.next = _update2;
+ }
+ queue.last = _update2;
+
+ if (
+ fiber.expirationTime === NoWork &&
+ (alternate === null || alternate.expirationTime === NoWork)
+ ) {
+ // The queue is currently empty, which means we can eagerly compute the
+ // next state before entering the render phase. If the new state is the
+ // same as the current state, we may be able to bail out entirely.
+ var _eagerReducer = queue.eagerReducer;
+ if (_eagerReducer !== null) {
+ var prevDispatcher = void 0;
+ {
+ prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ }
+ try {
+ var currentState = queue.eagerState;
+ var _eagerState = _eagerReducer(currentState, action);
+ // Stash the eagerly computed state, and the reducer used to compute
+ // it, on the update object. If the reducer hasn't changed by the
+ // time we enter the render phase, then the eager state can be used
+ // without calling the reducer again.
+ _update2.eagerReducer = _eagerReducer;
+ _update2.eagerState = _eagerState;
+ if (is(_eagerState, currentState)) {
+ // Fast path. We can bail out without scheduling React to re-render.
+ // It's still possible that we'll need to rebase this update later,
+ // if the component re-renders for a different reason and by that
+ // time the reducer has changed.
+ return;
+ }
+ } catch (error) {
+ // Suppress the error. It will throw again in the render phase.
+ } finally {
+ {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ }
+ }
+ }
+ {
+ if (shouldWarnForUnbatchedSetState === true) {
+ warnIfNotCurrentlyBatchingInDev(fiber);
+ }
+ }
+ scheduleWork(fiber, _expirationTime);
+ }
+}
+
+var ContextOnlyDispatcher = {
+ readContext: readContext,
+
+ useCallback: throwInvalidHookError,
+ useContext: throwInvalidHookError,
+ useEffect: throwInvalidHookError,
+ useImperativeHandle: throwInvalidHookError,
+ useLayoutEffect: throwInvalidHookError,
+ useMemo: throwInvalidHookError,
+ useReducer: throwInvalidHookError,
+ useRef: throwInvalidHookError,
+ useState: throwInvalidHookError,
+ useDebugValue: throwInvalidHookError
+};
+
+var HooksDispatcherOnMountInDEV = null;
+var HooksDispatcherOnUpdateInDEV = null;
+var InvalidNestedHooksDispatcherOnMountInDEV = null;
+var InvalidNestedHooksDispatcherOnUpdateInDEV = null;
+
+{
+ var warnInvalidContextAccess = function() {
+ warning$1(
+ false,
+ "Context can only be read while React is rendering. " +
+ "In classes, you can read it in the render method or getDerivedStateFromProps. " +
+ "In function components, you can read it directly in the function body, but not " +
+ "inside Hooks like useReducer() or useMemo()."
+ );
+ };
+
+ var warnInvalidHookAccess = function() {
+ warning$1(
+ false,
+ "Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. " +
+ "You can only call Hooks at the top level of your React function. " +
+ "For more information, see " +
+ "https://fb.me/rules-of-hooks"
+ );
+ };
+
+ HooksDispatcherOnMountInDEV = {
+ readContext: function(context, observedBits) {
+ return readContext(context, observedBits);
+ },
+ useCallback: function(callback, deps) {
+ currentHookNameInDev = "useCallback";
+ return mountCallback(callback, deps);
+ },
+ useContext: function(context, observedBits) {
+ currentHookNameInDev = "useContext";
+ return mountContext(context, observedBits);
+ },
+ useEffect: function(create, deps) {
+ currentHookNameInDev = "useEffect";
+ return mountEffect(create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ currentHookNameInDev = "useImperativeHandle";
+ return mountImperativeHandle(ref, create, deps);
+ },
+ useLayoutEffect: function(create, deps) {
+ currentHookNameInDev = "useLayoutEffect";
+ return mountLayoutEffect(create, deps);
+ },
+ useMemo: function(create, deps) {
+ currentHookNameInDev = "useMemo";
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
+ try {
+ return mountMemo(create, deps);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useReducer: function(reducer, initialArg, init) {
+ currentHookNameInDev = "useReducer";
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
+ try {
+ return mountReducer(reducer, initialArg, init);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useRef: function(initialValue) {
+ currentHookNameInDev = "useRef";
+ return mountRef(initialValue);
+ },
+ useState: function(initialState) {
+ currentHookNameInDev = "useState";
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
+ try {
+ return mountState(initialState);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useDebugValue: function(value, formatterFn) {
+ currentHookNameInDev = "useDebugValue";
+ return mountDebugValue(value, formatterFn);
+ }
+ };
+
+ HooksDispatcherOnUpdateInDEV = {
+ readContext: function(context, observedBits) {
+ return readContext(context, observedBits);
+ },
+ useCallback: function(callback, deps) {
+ currentHookNameInDev = "useCallback";
+ return updateCallback(callback, deps);
+ },
+ useContext: function(context, observedBits) {
+ currentHookNameInDev = "useContext";
+ return updateContext(context, observedBits);
+ },
+ useEffect: function(create, deps) {
+ currentHookNameInDev = "useEffect";
+ return updateEffect(create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ currentHookNameInDev = "useImperativeHandle";
+ return updateImperativeHandle(ref, create, deps);
+ },
+ useLayoutEffect: function(create, deps) {
+ currentHookNameInDev = "useLayoutEffect";
+ return updateLayoutEffect(create, deps);
+ },
+ useMemo: function(create, deps) {
+ currentHookNameInDev = "useMemo";
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ try {
+ return updateMemo(create, deps);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useReducer: function(reducer, initialArg, init) {
+ currentHookNameInDev = "useReducer";
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ try {
+ return updateReducer(reducer, initialArg, init);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useRef: function(initialValue) {
+ currentHookNameInDev = "useRef";
+ return updateRef(initialValue);
+ },
+ useState: function(initialState) {
+ currentHookNameInDev = "useState";
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ try {
+ return updateState(initialState);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useDebugValue: function(value, formatterFn) {
+ currentHookNameInDev = "useDebugValue";
+ return updateDebugValue(value, formatterFn);
+ }
+ };
+
+ InvalidNestedHooksDispatcherOnMountInDEV = {
+ readContext: function(context, observedBits) {
+ warnInvalidContextAccess();
+ return readContext(context, observedBits);
+ },
+ useCallback: function(callback, deps) {
+ currentHookNameInDev = "useCallback";
+ warnInvalidHookAccess();
+ return mountCallback(callback, deps);
+ },
+ useContext: function(context, observedBits) {
+ currentHookNameInDev = "useContext";
+ warnInvalidHookAccess();
+ return mountContext(context, observedBits);
+ },
+ useEffect: function(create, deps) {
+ currentHookNameInDev = "useEffect";
+ warnInvalidHookAccess();
+ return mountEffect(create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ currentHookNameInDev = "useImperativeHandle";
+ warnInvalidHookAccess();
+ return mountImperativeHandle(ref, create, deps);
+ },
+ useLayoutEffect: function(create, deps) {
+ currentHookNameInDev = "useLayoutEffect";
+ warnInvalidHookAccess();
+ return mountLayoutEffect(create, deps);
+ },
+ useMemo: function(create, deps) {
+ currentHookNameInDev = "useMemo";
+ warnInvalidHookAccess();
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
+ try {
+ return mountMemo(create, deps);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useReducer: function(reducer, initialArg, init) {
+ currentHookNameInDev = "useReducer";
+ warnInvalidHookAccess();
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
+ try {
+ return mountReducer(reducer, initialArg, init);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useRef: function(initialValue) {
+ currentHookNameInDev = "useRef";
+ warnInvalidHookAccess();
+ return mountRef(initialValue);
+ },
+ useState: function(initialState) {
+ currentHookNameInDev = "useState";
+ warnInvalidHookAccess();
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
+ try {
+ return mountState(initialState);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useDebugValue: function(value, formatterFn) {
+ currentHookNameInDev = "useDebugValue";
+ warnInvalidHookAccess();
+ return mountDebugValue(value, formatterFn);
+ }
+ };
+
+ InvalidNestedHooksDispatcherOnUpdateInDEV = {
+ readContext: function(context, observedBits) {
+ warnInvalidContextAccess();
+ return readContext(context, observedBits);
+ },
+ useCallback: function(callback, deps) {
+ currentHookNameInDev = "useCallback";
+ warnInvalidHookAccess();
+ return updateCallback(callback, deps);
+ },
+ useContext: function(context, observedBits) {
+ currentHookNameInDev = "useContext";
+ warnInvalidHookAccess();
+ return updateContext(context, observedBits);
+ },
+ useEffect: function(create, deps) {
+ currentHookNameInDev = "useEffect";
+ warnInvalidHookAccess();
+ return updateEffect(create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ currentHookNameInDev = "useImperativeHandle";
+ warnInvalidHookAccess();
+ return updateImperativeHandle(ref, create, deps);
+ },
+ useLayoutEffect: function(create, deps) {
+ currentHookNameInDev = "useLayoutEffect";
+ warnInvalidHookAccess();
+ return updateLayoutEffect(create, deps);
+ },
+ useMemo: function(create, deps) {
+ currentHookNameInDev = "useMemo";
+ warnInvalidHookAccess();
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ try {
+ return updateMemo(create, deps);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useReducer: function(reducer, initialArg, init) {
+ currentHookNameInDev = "useReducer";
+ warnInvalidHookAccess();
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ try {
+ return updateReducer(reducer, initialArg, init);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useRef: function(initialValue) {
+ currentHookNameInDev = "useRef";
+ warnInvalidHookAccess();
+ return updateRef(initialValue);
+ },
+ useState: function(initialState) {
+ currentHookNameInDev = "useState";
+ warnInvalidHookAccess();
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ try {
+ return updateState(initialState);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useDebugValue: function(value, formatterFn) {
+ currentHookNameInDev = "useDebugValue";
+ warnInvalidHookAccess();
+ return updateDebugValue(value, formatterFn);
+ }
+ };
+}
+
+var commitTime = 0;
+var profilerStartTime = -1;
+
+function getCommitTime() {
+ return commitTime;
+}
+
+function recordCommitTime() {
+ if (!enableProfilerTimer) {
+ return;
+ }
+ commitTime = now$$1();
+}
+
+function startProfilerTimer(fiber) {
+ if (!enableProfilerTimer) {
+ return;
+ }
+
+ profilerStartTime = now$$1();
+
+ if (fiber.actualStartTime < 0) {
+ fiber.actualStartTime = now$$1();
+ }
+}
+
+function stopProfilerTimerIfRunning(fiber) {
+ if (!enableProfilerTimer) {
+ return;
+ }
+ profilerStartTime = -1;
+}
+
+function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) {
+ if (!enableProfilerTimer) {
+ return;
+ }
+
+ if (profilerStartTime >= 0) {
+ var elapsedTime = now$$1() - profilerStartTime;
+ fiber.actualDuration += elapsedTime;
+ if (overrideBaseTime) {
+ fiber.selfBaseDuration = elapsedTime;
+ }
+ profilerStartTime = -1;
+ }
+}
+
// The deepest Fiber on the stack involved in a hydration context.
// This may have been an insertion or a hydration.
var hydrationParentFiber = null;
@@ -10766,6 +10608,18 @@
return true;
}
+function reenterHydrationStateFromDehydratedSuspenseInstance(fiber) {
+ if (!supportsHydration) {
+ return false;
+ }
+
+ var suspenseInstance = fiber.stateNode;
+ nextHydratableInstance = getNextHydratableSibling(suspenseInstance);
+ popToNextHostParent(fiber);
+ isHydrating = true;
+ return true;
+}
+
function deleteHydratableInstance(returnFiber, instance) {
{
switch (returnFiber.tag) {
@@ -10820,6 +10674,9 @@
var text = fiber.pendingProps;
didNotFindHydratableContainerTextInstance(parentContainer, text);
break;
+ case SuspenseComponent:
+ didNotFindHydratableContainerSuspenseInstance(parentContainer);
+ break;
}
break;
}
@@ -10848,6 +10705,13 @@
_text
);
break;
+ case SuspenseComponent:
+ didNotFindHydratableSuspenseInstance(
+ parentType,
+ parentProps,
+ parentInstance
+ );
+ break;
}
break;
}
@@ -10878,6 +10742,18 @@
}
return false;
}
+ case SuspenseComponent: {
+ if (enableSuspenseServerRenderer) {
+ var suspenseInstance = canHydrateSuspenseInstance(nextInstance);
+ if (suspenseInstance !== null) {
+ // Downgrade the tag to a dehydrated component until we've hydrated it.
+ fiber.tag = DehydratedSuspenseComponent;
+ fiber.stateNode = suspenseInstance;
+ return true;
+ }
+ }
+ return false;
+ }
default:
return false;
}
@@ -10998,12 +10874,32 @@
return shouldUpdate;
}
+function skipPastDehydratedSuspenseInstance(fiber) {
+ if (!supportsHydration) {
+ invariant(
+ false,
+ "Expected skipPastDehydratedSuspenseInstance() to never be called. " +
+ "This error is likely caused by a bug in React. Please file an issue."
+ );
+ }
+ var suspenseInstance = fiber.stateNode;
+ invariant(
+ suspenseInstance,
+ "Expected to have a hydrated suspense instance. " +
+ "This error is likely caused by a bug in React. Please file an issue."
+ );
+ nextHydratableInstance = getNextHydratableInstanceAfterSuspenseInstance(
+ suspenseInstance
+ );
+}
+
function popToNextHostParent(fiber) {
var parent = fiber.return;
while (
parent !== null &&
parent.tag !== HostComponent &&
- parent.tag !== HostRoot
+ parent.tag !== HostRoot &&
+ parent.tag !== DehydratedSuspenseComponent
) {
parent = parent.return;
}
@@ -11067,6 +10963,8 @@
var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner;
+var didReceiveUpdate = false;
+
var didWarnAboutBadClass = void 0;
var didWarnAboutContextTypeOnFunctionComponent = void 0;
var didWarnAboutGetDerivedStateOnFunctionComponent = void 0;
@@ -11153,6 +11051,10 @@
nextProps,
renderExpirationTime
) {
+ // TODO: current can be non-null here even if the component
+ // hasn't yet mounted. This happens after the first render suspends.
+ // We'll need to figure out if this is fine or can cause issues.
+
{
if (workInProgress.type !== workInProgress.elementType) {
// Lazy component props can't be validated in createElement
@@ -11176,14 +11078,45 @@
// The rest is a fork of updateFunctionComponent
var nextChildren = void 0;
prepareToReadContext(workInProgress, renderExpirationTime);
- prepareToUseHooks(current$$1, workInProgress, renderExpirationTime);
{
ReactCurrentOwner$3.current = workInProgress;
setCurrentPhase("render");
- nextChildren = render(nextProps, ref);
+ nextChildren = renderWithHooks(
+ current$$1,
+ workInProgress,
+ render,
+ nextProps,
+ ref,
+ renderExpirationTime
+ );
+ if (
+ debugRenderPhaseSideEffects ||
+ (debugRenderPhaseSideEffectsForStrictMode &&
+ workInProgress.mode & StrictMode)
+ ) {
+ // Only double-render components with Hooks
+ if (workInProgress.memoizedState !== null) {
+ nextChildren = renderWithHooks(
+ current$$1,
+ workInProgress,
+ render,
+ nextProps,
+ ref,
+ renderExpirationTime
+ );
+ }
+ }
setCurrentPhase(null);
}
- nextChildren = finishHooks(render, nextProps, nextChildren, ref);
+
+ if (current$$1 !== null && !didReceiveUpdate) {
+ bailoutHooks(current$$1, workInProgress, renderExpirationTime);
+ return bailoutOnAlreadyFinishedWork(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+ );
+ }
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
@@ -11311,6 +11244,10 @@
updateExpirationTime,
renderExpirationTime
) {
+ // TODO: current can be non-null here even if the component
+ // hasn't yet mounted. This happens when the inner render suspends.
+ // We'll need to figure out if this is fine or can cause issues.
+
{
if (workInProgress.type !== workInProgress.elementType) {
// Lazy component props can't be validated in createElement
@@ -11335,12 +11272,14 @@
// Inner propTypes will be validated in the function component path.
}
}
- if (current$$1 !== null && updateExpirationTime < renderExpirationTime) {
+ if (current$$1 !== null) {
var prevProps = current$$1.memoizedProps;
if (
shallowEqual(prevProps, nextProps) &&
current$$1.ref === workInProgress.ref
) {
+ didReceiveUpdate = false;
+ if (updateExpirationTime < renderExpirationTime) {
return bailoutOnAlreadyFinishedWork(
current$$1,
workInProgress,
@@ -11348,6 +11287,7 @@
);
}
}
+ }
return updateFunctionComponent(
current$$1,
workInProgress,
@@ -11434,14 +11374,45 @@
var nextChildren = void 0;
prepareToReadContext(workInProgress, renderExpirationTime);
- prepareToUseHooks(current$$1, workInProgress, renderExpirationTime);
{
ReactCurrentOwner$3.current = workInProgress;
setCurrentPhase("render");
- nextChildren = Component(nextProps, context);
+ nextChildren = renderWithHooks(
+ current$$1,
+ workInProgress,
+ Component,
+ nextProps,
+ context,
+ renderExpirationTime
+ );
+ if (
+ debugRenderPhaseSideEffects ||
+ (debugRenderPhaseSideEffectsForStrictMode &&
+ workInProgress.mode & StrictMode)
+ ) {
+ // Only double-render components with Hooks
+ if (workInProgress.memoizedState !== null) {
+ nextChildren = renderWithHooks(
+ current$$1,
+ workInProgress,
+ Component,
+ nextProps,
+ context,
+ renderExpirationTime
+ );
+ }
+ }
setCurrentPhase(null);
}
- nextChildren = finishHooks(Component, nextProps, nextChildren, context);
+
+ if (current$$1 !== null && !didReceiveUpdate) {
+ bailoutHooks(current$$1, workInProgress, renderExpirationTime);
+ return bailoutOnAlreadyFinishedWork(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+ );
+ }
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
@@ -11776,7 +11747,7 @@
shouldDeprioritizeSubtree(type, nextProps)
) {
// Schedule this fiber to re-render at offscreen priority. Then bailout.
- workInProgress.expirationTime = Never;
+ workInProgress.expirationTime = workInProgress.childExpirationTime = Never;
return null;
}
@@ -11829,6 +11800,9 @@
var child = void 0;
switch (resolvedTag) {
case FunctionComponent: {
+ {
+ validateFunctionComponentInDev(workInProgress, Component);
+ }
child = updateFunctionComponent(
null,
workInProgress,
@@ -11989,7 +11963,6 @@
var context = getMaskedContext(workInProgress, unmaskedContext);
prepareToReadContext(workInProgress, renderExpirationTime);
- prepareToUseHooks(null, workInProgress, renderExpirationTime);
var value = void 0;
@@ -12017,7 +11990,14 @@
}
ReactCurrentOwner$3.current = workInProgress;
- value = Component(props, context);
+ value = renderWithHooks(
+ null,
+ workInProgress,
+ Component,
+ props,
+ context,
+ renderExpirationTime
+ );
}
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
@@ -12071,7 +12051,25 @@
} else {
// Proceed under the assumption that this is a function component
workInProgress.tag = FunctionComponent;
- value = finishHooks(Component, props, value, context);
+ {
+ if (
+ debugRenderPhaseSideEffects ||
+ (debugRenderPhaseSideEffectsForStrictMode &&
+ workInProgress.mode & StrictMode)
+ ) {
+ // Only double-render components with Hooks
+ if (workInProgress.memoizedState !== null) {
+ value = renderWithHooks(
+ null,
+ workInProgress,
+ Component,
+ props,
+ context,
+ renderExpirationTime
+ );
+ }
+ }
+ }
reconcileChildren(null, workInProgress, value, renderExpirationTime);
{
validateFunctionComponentInDev(workInProgress, Component);
@@ -12107,7 +12105,8 @@
warning$1(
false,
"Function components cannot be given refs. " +
- "Attempts to access this ref will fail.%s",
+ "Attempts to access this ref will fail. " +
+ "Did you mean to use React.forwardRef()?%s",
info
);
}
@@ -12202,6 +12201,22 @@
// children -- we skip over the primary children entirely.
var next = void 0;
if (current$$1 === null) {
+ if (enableSuspenseServerRenderer) {
+ // If we're currently hydrating, try to hydrate this boundary.
+ // But only if this has a fallback.
+ if (nextProps.fallback !== undefined) {
+ tryToClaimNextHydratableInstance(workInProgress);
+ // This could've changed the tag if this was a dehydrated suspense component.
+ if (workInProgress.tag === DehydratedSuspenseComponent) {
+ return updateDehydratedSuspenseComponent(
+ null,
+ workInProgress,
+ renderExpirationTime
+ );
+ }
+ }
+ }
+
// This is the initial mount. This branch is pretty simple because there's
// no previous state that needs to be preserved.
if (nextDidTimeout) {
@@ -12396,6 +12411,7 @@
);
}
}
+ workInProgress.stateNode = current$$1.stateNode;
}
workInProgress.memoizedState = nextState;
@@ -12403,6 +12419,107 @@
return next;
}
+function updateDehydratedSuspenseComponent(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+) {
+ if (current$$1 === null) {
+ // During the first pass, we'll bail out and not drill into the children.
+ // Instead, we'll leave the content in place and try to hydrate it later.
+ workInProgress.expirationTime = Never;
+ return null;
+ }
+ if ((workInProgress.effectTag & DidCapture) !== NoEffect) {
+ // Something suspended. Leave the existing children in place.
+ // TODO: In non-concurrent mode, should we commit the nodes we have hydrated so far?
+ workInProgress.child = null;
+ return null;
+ }
+ // We use childExpirationTime to indicate that a child might depend on context, so if
+ // any context has changed, we need to treat is as if the input might have changed.
+ var hasContextChanged$$1 =
+ current$$1.childExpirationTime >= renderExpirationTime;
+ var suspenseInstance = current$$1.stateNode;
+ if (
+ didReceiveUpdate ||
+ hasContextChanged$$1 ||
+ isSuspenseInstanceFallback(suspenseInstance)
+ ) {
+ // This boundary has changed since the first render. This means that we are now unable to
+ // hydrate it. We might still be able to hydrate it using an earlier expiration time but
+ // during this render we can't. Instead, we're going to delete the whole subtree and
+ // instead inject a new real Suspense boundary to take its place, which may render content
+ // or fallback. The real Suspense boundary will suspend for a while so we have some time
+ // to ensure it can produce real content, but all state and pending events will be lost.
+
+ // Alternatively, this boundary is in a permanent fallback state. In this case, we'll never
+ // get an update and we'll never be able to hydrate the final content. Let's just try the
+ // client side render instead.
+
+ // Detach from the current dehydrated boundary.
+ current$$1.alternate = null;
+ workInProgress.alternate = null;
+
+ // Insert a deletion in the effect list.
+ var returnFiber = workInProgress.return;
+ invariant(
+ returnFiber !== null,
+ "Suspense boundaries are never on the root. " +
+ "This is probably a bug in React."
+ );
+ var last = returnFiber.lastEffect;
+ if (last !== null) {
+ last.nextEffect = current$$1;
+ returnFiber.lastEffect = current$$1;
+ } else {
+ returnFiber.firstEffect = returnFiber.lastEffect = current$$1;
+ }
+ current$$1.nextEffect = null;
+ current$$1.effectTag = Deletion;
+
+ // Upgrade this work in progress to a real Suspense component.
+ workInProgress.tag = SuspenseComponent;
+ workInProgress.stateNode = null;
+ workInProgress.memoizedState = null;
+ // This is now an insertion.
+ workInProgress.effectTag |= Placement;
+ // Retry as a real Suspense component.
+ return updateSuspenseComponent(null, workInProgress, renderExpirationTime);
+ } else if (isSuspenseInstancePending(suspenseInstance)) {
+ // This component is still pending more data from the server, so we can't hydrate its
+ // content. We treat it as if this component suspended itself. It might seem as if
+ // we could just try to render it client-side instead. However, this will perform a
+ // lot of unnecessary work and is unlikely to complete since it often will suspend
+ // on missing data anyway. Additionally, the server might be able to render more
+ // than we can on the client yet. In that case we'd end up with more fallback states
+ // on the client than if we just leave it alone. If the server times out or errors
+ // these should update this boundary to the permanent Fallback state instead.
+ // Mark it as having captured (i.e. suspended).
+ workInProgress.effectTag |= DidCapture;
+ // Leave the children in place. I.e. empty.
+ workInProgress.child = null;
+ // Register a callback to retry this boundary once the server has sent the result.
+ registerSuspenseInstanceRetry(
+ suspenseInstance,
+ retryTimedOutBoundary.bind(null, current$$1)
+ );
+ return null;
+ } else {
+ // This is the first attempt.
+ reenterHydrationStateFromDehydratedSuspenseInstance(workInProgress);
+ var nextProps = workInProgress.pendingProps;
+ var nextChildren = nextProps.children;
+ workInProgress.child = mountChildFibers(
+ workInProgress,
+ null,
+ nextChildren,
+ renderExpirationTime
+ );
+ return workInProgress.child;
+ }
+}
+
function updatePortalComponent(
current$$1,
workInProgress,
@@ -12566,6 +12683,10 @@
return workInProgress.child;
}
+function markWorkInProgressReceivedUpdate() {
+ didReceiveUpdate = true;
+}
+
function bailoutOnAlreadyFinishedWork(
current$$1,
workInProgress,
@@ -12575,7 +12696,7 @@
if (current$$1 !== null) {
// Reuse previous context list
- workInProgress.firstContextDependency = current$$1.firstContextDependency;
+ workInProgress.contextDependencies = current$$1.contextDependencies;
}
if (enableProfilerTimer) {
@@ -12604,11 +12725,13 @@
if (current$$1 !== null) {
var oldProps = current$$1.memoizedProps;
var newProps = workInProgress.pendingProps;
- if (
- oldProps === newProps &&
- !hasContextChanged() &&
- updateExpirationTime < renderExpirationTime
- ) {
+
+ if (oldProps !== newProps || hasContextChanged()) {
+ // If props or context changed, mark the fiber as having performed work.
+ // This may be unset if the props are determined to be equal later (memo).
+ didReceiveUpdate = true;
+ } else if (updateExpirationTime < renderExpirationTime) {
+ didReceiveUpdate = false;
// This fiber does not have any pending work. Bailout without entering
// the begin phase. There's still some bookkeeping we that needs to be done
// in this optimized path, mostly pushing stuff onto the stack.
@@ -12683,6 +12806,15 @@
}
break;
}
+ case DehydratedSuspenseComponent: {
+ if (enableSuspenseServerRenderer) {
+ // We know that this component will suspend again because if it has
+ // been unsuspended it has committed as a regular Suspense component.
+ // If it needs to be retried, it should have work scheduled on it.
+ workInProgress.effectTag |= DidCapture;
+ break;
+ }
+ }
}
return bailoutOnAlreadyFinishedWork(
current$$1,
@@ -12690,6 +12822,8 @@
renderExpirationTime
);
}
+ } else {
+ didReceiveUpdate = false;
}
// Before entering the begin phase, clear the expiration time.
@@ -12854,13 +12988,930 @@
renderExpirationTime
);
}
- default:
+ case DehydratedSuspenseComponent: {
+ if (enableSuspenseServerRenderer) {
+ return updateDehydratedSuspenseComponent(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+ );
+ }
+ break;
+ }
+ }
invariant(
false,
"Unknown unit of work tag. This error is likely caused by a bug in " +
"React. Please file an issue."
);
+}
+
+var valueCursor = createCursor(null);
+
+var rendererSigil = void 0;
+{
+ // Use this to detect multiple renderers using the same context
+ rendererSigil = {};
+}
+
+var currentlyRenderingFiber = null;
+var lastContextDependency = null;
+var lastContextWithAllBitsObserved = null;
+
+var isDisallowedContextReadInDEV = false;
+
+function resetContextDependences() {
+ // This is called right before React yields execution, to ensure `readContext`
+ // cannot be called outside the render phase.
+ currentlyRenderingFiber = null;
+ lastContextDependency = null;
+ lastContextWithAllBitsObserved = null;
+ {
+ isDisallowedContextReadInDEV = false;
+ }
+}
+
+function enterDisallowedContextReadInDEV() {
+ {
+ isDisallowedContextReadInDEV = true;
+ }
+}
+
+function exitDisallowedContextReadInDEV() {
+ {
+ isDisallowedContextReadInDEV = false;
+ }
+}
+
+function pushProvider(providerFiber, nextValue) {
+ var context = providerFiber.type._context;
+
+ if (isPrimaryRenderer) {
+ push(valueCursor, context._currentValue, providerFiber);
+
+ context._currentValue = nextValue;
+ {
+ !(
+ context._currentRenderer === undefined ||
+ context._currentRenderer === null ||
+ context._currentRenderer === rendererSigil
+ )
+ ? warningWithoutStack$1(
+ false,
+ "Detected multiple renderers concurrently rendering the " +
+ "same context provider. This is currently unsupported."
+ )
+ : void 0;
+ context._currentRenderer = rendererSigil;
+ }
+ } else {
+ push(valueCursor, context._currentValue2, providerFiber);
+
+ context._currentValue2 = nextValue;
+ {
+ !(
+ context._currentRenderer2 === undefined ||
+ context._currentRenderer2 === null ||
+ context._currentRenderer2 === rendererSigil
+ )
+ ? warningWithoutStack$1(
+ false,
+ "Detected multiple renderers concurrently rendering the " +
+ "same context provider. This is currently unsupported."
+ )
+ : void 0;
+ context._currentRenderer2 = rendererSigil;
+ }
+ }
+}
+
+function popProvider(providerFiber) {
+ var currentValue = valueCursor.current;
+
+ pop(valueCursor, providerFiber);
+
+ var context = providerFiber.type._context;
+ if (isPrimaryRenderer) {
+ context._currentValue = currentValue;
+ } else {
+ context._currentValue2 = currentValue;
+ }
+}
+
+function calculateChangedBits(context, newValue, oldValue) {
+ if (is(oldValue, newValue)) {
+ // No change
+ return 0;
+ } else {
+ var changedBits =
+ typeof context._calculateChangedBits === "function"
+ ? context._calculateChangedBits(oldValue, newValue)
+ : maxSigned31BitInt;
+
+ {
+ !((changedBits & maxSigned31BitInt) === changedBits)
+ ? warning$1(
+ false,
+ "calculateChangedBits: Expected the return value to be a " +
+ "31-bit integer. Instead received: %s",
+ changedBits
+ )
+ : void 0;
+ }
+ return changedBits | 0;
+ }
+}
+
+function scheduleWorkOnParentPath(parent, renderExpirationTime) {
+ // Update the child expiration time of all the ancestors, including
+ // the alternates.
+ var node = parent;
+ while (node !== null) {
+ var alternate = node.alternate;
+ if (node.childExpirationTime < renderExpirationTime) {
+ node.childExpirationTime = renderExpirationTime;
+ if (
+ alternate !== null &&
+ alternate.childExpirationTime < renderExpirationTime
+ ) {
+ alternate.childExpirationTime = renderExpirationTime;
+ }
+ } else if (
+ alternate !== null &&
+ alternate.childExpirationTime < renderExpirationTime
+ ) {
+ alternate.childExpirationTime = renderExpirationTime;
+ } else {
+ // Neither alternate was updated, which means the rest of the
+ // ancestor path already has sufficient priority.
+ break;
+ }
+ node = node.return;
+ }
+}
+
+function propagateContextChange(
+ workInProgress,
+ context,
+ changedBits,
+ renderExpirationTime
+) {
+ var fiber = workInProgress.child;
+ if (fiber !== null) {
+ // Set the return pointer of the child to the work-in-progress fiber.
+ fiber.return = workInProgress;
+ }
+ while (fiber !== null) {
+ var nextFiber = void 0;
+
+ // Visit this fiber.
+ var list = fiber.contextDependencies;
+ if (list !== null) {
+ nextFiber = fiber.child;
+
+ var dependency = list.first;
+ while (dependency !== null) {
+ // Check if the context matches.
+ if (
+ dependency.context === context &&
+ (dependency.observedBits & changedBits) !== 0
+ ) {
+ // Match! Schedule an update on this fiber.
+
+ if (fiber.tag === ClassComponent) {
+ // Schedule a force update on the work-in-progress.
+ var update = createUpdate(renderExpirationTime);
+ update.tag = ForceUpdate;
+ // TODO: Because we don't have a work-in-progress, this will add the
+ // update to the current fiber, too, which means it will persist even if
+ // this render is thrown away. Since it's a race condition, not sure it's
+ // worth fixing.
+ enqueueUpdate(fiber, update);
+ }
+
+ if (fiber.expirationTime < renderExpirationTime) {
+ fiber.expirationTime = renderExpirationTime;
+ }
+ var alternate = fiber.alternate;
+ if (
+ alternate !== null &&
+ alternate.expirationTime < renderExpirationTime
+ ) {
+ alternate.expirationTime = renderExpirationTime;
+ }
+
+ scheduleWorkOnParentPath(fiber.return, renderExpirationTime);
+
+ // Mark the expiration time on the list, too.
+ if (list.expirationTime < renderExpirationTime) {
+ list.expirationTime = renderExpirationTime;
+ }
+
+ // Since we already found a match, we can stop traversing the
+ // dependency list.
+ break;
+ }
+ dependency = dependency.next;
+ }
+ } else if (fiber.tag === ContextProvider) {
+ // Don't scan deeper if this is a matching provider
+ nextFiber = fiber.type === workInProgress.type ? null : fiber.child;
+ } else if (
+ enableSuspenseServerRenderer &&
+ fiber.tag === DehydratedSuspenseComponent
+ ) {
+ // If a dehydrated suspense component is in this subtree, we don't know
+ // if it will have any context consumers in it. The best we can do is
+ // mark it as having updates on its children.
+ if (fiber.expirationTime < renderExpirationTime) {
+ fiber.expirationTime = renderExpirationTime;
+ }
+ var _alternate = fiber.alternate;
+ if (
+ _alternate !== null &&
+ _alternate.expirationTime < renderExpirationTime
+ ) {
+ _alternate.expirationTime = renderExpirationTime;
+ }
+ // This is intentionally passing this fiber as the parent
+ // because we want to schedule this fiber as having work
+ // on its children. We'll use the childExpirationTime on
+ // this fiber to indicate that a context has changed.
+ scheduleWorkOnParentPath(fiber, renderExpirationTime);
+ nextFiber = fiber.sibling;
+ } else {
+ // Traverse down.
+ nextFiber = fiber.child;
+ }
+
+ if (nextFiber !== null) {
+ // Set the return pointer of the child to the work-in-progress fiber.
+ nextFiber.return = fiber;
+ } else {
+ // No child. Traverse to next sibling.
+ nextFiber = fiber;
+ while (nextFiber !== null) {
+ if (nextFiber === workInProgress) {
+ // We're back to the root of this subtree. Exit.
+ nextFiber = null;
+ break;
+ }
+ var sibling = nextFiber.sibling;
+ if (sibling !== null) {
+ // Set the return pointer of the sibling to the work-in-progress fiber.
+ sibling.return = nextFiber.return;
+ nextFiber = sibling;
+ break;
+ }
+ // No more siblings. Traverse up.
+ nextFiber = nextFiber.return;
+ }
+ }
+ fiber = nextFiber;
+ }
+}
+
+function prepareToReadContext(workInProgress, renderExpirationTime) {
+ currentlyRenderingFiber = workInProgress;
+ lastContextDependency = null;
+ lastContextWithAllBitsObserved = null;
+
+ var currentDependencies = workInProgress.contextDependencies;
+ if (
+ currentDependencies !== null &&
+ currentDependencies.expirationTime >= renderExpirationTime
+ ) {
+ // Context list has a pending update. Mark that this fiber performed work.
+ markWorkInProgressReceivedUpdate();
+ }
+
+ // Reset the work-in-progress list
+ workInProgress.contextDependencies = null;
+}
+
+function readContext(context, observedBits) {
+ {
+ // This warning would fire if you read context inside a Hook like useMemo.
+ // Unlike the class check below, it's not enforced in production for perf.
+ !!isDisallowedContextReadInDEV
+ ? warning$1(
+ false,
+ "Context can only be read while React is rendering. " +
+ "In classes, you can read it in the render method or getDerivedStateFromProps. " +
+ "In function components, you can read it directly in the function body, but not " +
+ "inside Hooks like useReducer() or useMemo()."
+ )
+ : void 0;
+ }
+
+ if (lastContextWithAllBitsObserved === context) {
+ // Nothing to do. We already observe everything in this context.
+ } else if (observedBits === false || observedBits === 0) {
+ // Do not observe any updates.
+ } else {
+ var resolvedObservedBits = void 0; // Avoid deopting on observable arguments or heterogeneous types.
+ if (
+ typeof observedBits !== "number" ||
+ observedBits === maxSigned31BitInt
+ ) {
+ // Observe all updates.
+ lastContextWithAllBitsObserved = context;
+ resolvedObservedBits = maxSigned31BitInt;
+ } else {
+ resolvedObservedBits = observedBits;
+ }
+
+ var contextItem = {
+ context: context,
+ observedBits: resolvedObservedBits,
+ next: null
+ };
+
+ if (lastContextDependency === null) {
+ invariant(
+ currentlyRenderingFiber !== null,
+ "Context can only be read while React is rendering. " +
+ "In classes, you can read it in the render method or getDerivedStateFromProps. " +
+ "In function components, you can read it directly in the function body, but not " +
+ "inside Hooks like useReducer() or useMemo()."
+ );
+
+ // This is the first dependency for this component. Create a new list.
+ lastContextDependency = contextItem;
+ currentlyRenderingFiber.contextDependencies = {
+ first: contextItem,
+ expirationTime: NoWork
+ };
+ } else {
+ // Append a new context item.
+ lastContextDependency = lastContextDependency.next = contextItem;
+ }
+ }
+ return isPrimaryRenderer ? context._currentValue : context._currentValue2;
+}
+
+// UpdateQueue is a linked list of prioritized updates.
+//
+// Like fibers, update queues come in pairs: a current queue, which represents
+// the visible state of the screen, and a work-in-progress queue, which can be
+// mutated and processed asynchronously before it is committed — a form of
+// double buffering. If a work-in-progress render is discarded before finishing,
+// we create a new work-in-progress by cloning the current queue.
+//
+// Both queues share a persistent, singly-linked list structure. To schedule an
+// update, we append it to the end of both queues. Each queue maintains a
+// pointer to first update in the persistent list that hasn't been processed.
+// The work-in-progress pointer always has a position equal to or greater than
+// the current queue, since we always work on that one. The current queue's
+// pointer is only updated during the commit phase, when we swap in the
+// work-in-progress.
+//
+// For example:
+//
+// Current pointer: A - B - C - D - E - F
+// Work-in-progress pointer: D - E - F
+// ^
+// The work-in-progress queue has
+// processed more updates than current.
+//
+// The reason we append to both queues is because otherwise we might drop
+// updates without ever processing them. For example, if we only add updates to
+// the work-in-progress queue, some updates could be lost whenever a work-in
+// -progress render restarts by cloning from current. Similarly, if we only add
+// updates to the current queue, the updates will be lost whenever an already
+// in-progress queue commits and swaps with the current queue. However, by
+// adding to both queues, we guarantee that the update will be part of the next
+// work-in-progress. (And because the work-in-progress queue becomes the
+// current queue once it commits, there's no danger of applying the same
+// update twice.)
+//
+// Prioritization
+// --------------
+//
+// Updates are not sorted by priority, but by insertion; new updates are always
+// appended to the end of the list.
+//
+// The priority is still important, though. When processing the update queue
+// during the render phase, only the updates with sufficient priority are
+// included in the result. If we skip an update because it has insufficient
+// priority, it remains in the queue to be processed later, during a lower
+// priority render. Crucially, all updates subsequent to a skipped update also
+// remain in the queue *regardless of their priority*. That means high priority
+// updates are sometimes processed twice, at two separate priorities. We also
+// keep track of a base state, that represents the state before the first
+// update in the queue is applied.
+//
+// For example:
+//
+// Given a base state of '', and the following queue of updates
+//
+// A1 - B2 - C1 - D2
+//
+// where the number indicates the priority, and the update is applied to the
+// previous state by appending a letter, React will process these updates as
+// two separate renders, one per distinct priority level:
+//
+// First render, at priority 1:
+// Base state: ''
+// Updates: [A1, C1]
+// Result state: 'AC'
+//
+// Second render, at priority 2:
+// Base state: 'A' <- The base state does not include C1,
+// because B2 was skipped.
+// Updates: [B2, C1, D2] <- C1 was rebased on top of B2
+// Result state: 'ABCD'
+//
+// Because we process updates in insertion order, and rebase high priority
+// updates when preceding updates are skipped, the final result is deterministic
+// regardless of priority. Intermediate state may vary according to system
+// resources, but the final state is always the same.
+
+var UpdateState = 0;
+var ReplaceState = 1;
+var ForceUpdate = 2;
+var CaptureUpdate = 3;
+
+// Global state that is reset at the beginning of calling `processUpdateQueue`.
+// It should only be read right after calling `processUpdateQueue`, via
+// `checkHasForceUpdateAfterProcessing`.
+var hasForceUpdate = false;
+
+var didWarnUpdateInsideUpdate = void 0;
+var currentlyProcessingQueue = void 0;
+var resetCurrentlyProcessingQueue = void 0;
+{
+ didWarnUpdateInsideUpdate = false;
+ currentlyProcessingQueue = null;
+ resetCurrentlyProcessingQueue = function() {
+ currentlyProcessingQueue = null;
+ };
+}
+
+function createUpdateQueue(baseState) {
+ var queue = {
+ baseState: baseState,
+ firstUpdate: null,
+ lastUpdate: null,
+ firstCapturedUpdate: null,
+ lastCapturedUpdate: null,
+ firstEffect: null,
+ lastEffect: null,
+ firstCapturedEffect: null,
+ lastCapturedEffect: null
+ };
+ return queue;
+}
+
+function cloneUpdateQueue(currentQueue) {
+ var queue = {
+ baseState: currentQueue.baseState,
+ firstUpdate: currentQueue.firstUpdate,
+ lastUpdate: currentQueue.lastUpdate,
+
+ // TODO: With resuming, if we bail out and resuse the child tree, we should
+ // keep these effects.
+ firstCapturedUpdate: null,
+ lastCapturedUpdate: null,
+
+ firstEffect: null,
+ lastEffect: null,
+
+ firstCapturedEffect: null,
+ lastCapturedEffect: null
+ };
+ return queue;
+}
+
+function createUpdate(expirationTime) {
+ return {
+ expirationTime: expirationTime,
+
+ tag: UpdateState,
+ payload: null,
+ callback: null,
+
+ next: null,
+ nextEffect: null
+ };
+}
+
+function appendUpdateToQueue(queue, update) {
+ // Append the update to the end of the list.
+ if (queue.lastUpdate === null) {
+ // Queue is empty
+ queue.firstUpdate = queue.lastUpdate = update;
+ } else {
+ queue.lastUpdate.next = update;
+ queue.lastUpdate = update;
+ }
+}
+
+function enqueueUpdate(fiber, update) {
+ // Update queues are created lazily.
+ var alternate = fiber.alternate;
+ var queue1 = void 0;
+ var queue2 = void 0;
+ if (alternate === null) {
+ // There's only one fiber.
+ queue1 = fiber.updateQueue;
+ queue2 = null;
+ if (queue1 === null) {
+ queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
+ }
+ } else {
+ // There are two owners.
+ queue1 = fiber.updateQueue;
+ queue2 = alternate.updateQueue;
+ if (queue1 === null) {
+ if (queue2 === null) {
+ // Neither fiber has an update queue. Create new ones.
+ queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
+ queue2 = alternate.updateQueue = createUpdateQueue(
+ alternate.memoizedState
+ );
+ } else {
+ // Only one fiber has an update queue. Clone to create a new one.
+ queue1 = fiber.updateQueue = cloneUpdateQueue(queue2);
+ }
+ } else {
+ if (queue2 === null) {
+ // Only one fiber has an update queue. Clone to create a new one.
+ queue2 = alternate.updateQueue = cloneUpdateQueue(queue1);
+ } else {
+ // Both owners have an update queue.
+ }
+ }
+ }
+ if (queue2 === null || queue1 === queue2) {
+ // There's only a single queue.
+ appendUpdateToQueue(queue1, update);
+ } else {
+ // There are two queues. We need to append the update to both queues,
+ // while accounting for the persistent structure of the list — we don't
+ // want the same update to be added multiple times.
+ if (queue1.lastUpdate === null || queue2.lastUpdate === null) {
+ // One of the queues is not empty. We must add the update to both queues.
+ appendUpdateToQueue(queue1, update);
+ appendUpdateToQueue(queue2, update);
+ } else {
+ // Both queues are non-empty. The last update is the same in both lists,
+ // because of structural sharing. So, only append to one of the lists.
+ appendUpdateToQueue(queue1, update);
+ // But we still need to update the `lastUpdate` pointer of queue2.
+ queue2.lastUpdate = update;
+ }
+ }
+
+ {
+ if (
+ fiber.tag === ClassComponent &&
+ (currentlyProcessingQueue === queue1 ||
+ (queue2 !== null && currentlyProcessingQueue === queue2)) &&
+ !didWarnUpdateInsideUpdate
+ ) {
+ warningWithoutStack$1(
+ false,
+ "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."
+ );
+ didWarnUpdateInsideUpdate = true;
+ }
+ }
+}
+
+function enqueueCapturedUpdate(workInProgress, update) {
+ // Captured updates go into a separate list, and only on the work-in-
+ // progress queue.
+ var workInProgressQueue = workInProgress.updateQueue;
+ if (workInProgressQueue === null) {
+ workInProgressQueue = workInProgress.updateQueue = createUpdateQueue(
+ workInProgress.memoizedState
+ );
+ } else {
+ // TODO: I put this here rather than createWorkInProgress so that we don't
+ // clone the queue unnecessarily. There's probably a better way to
+ // structure this.
+ workInProgressQueue = ensureWorkInProgressQueueIsAClone(
+ workInProgress,
+ workInProgressQueue
+ );
+ }
+
+ // Append the update to the end of the list.
+ if (workInProgressQueue.lastCapturedUpdate === null) {
+ // This is the first render phase update
+ workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update;
+ } else {
+ workInProgressQueue.lastCapturedUpdate.next = update;
+ workInProgressQueue.lastCapturedUpdate = update;
+ }
+}
+
+function ensureWorkInProgressQueueIsAClone(workInProgress, queue) {
+ var current = workInProgress.alternate;
+ if (current !== null) {
+ // If the work-in-progress queue is equal to the current queue,
+ // we need to clone it first.
+ if (queue === current.updateQueue) {
+ queue = workInProgress.updateQueue = cloneUpdateQueue(queue);
+ }
+ }
+ return queue;
+}
+
+function getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ prevState,
+ nextProps,
+ instance
+) {
+ switch (update.tag) {
+ case ReplaceState: {
+ var _payload = update.payload;
+ if (typeof _payload === "function") {
+ // Updater function
+ {
+ enterDisallowedContextReadInDEV();
+ if (
+ debugRenderPhaseSideEffects ||
+ (debugRenderPhaseSideEffectsForStrictMode &&
+ workInProgress.mode & StrictMode)
+ ) {
+ _payload.call(instance, prevState, nextProps);
+ }
+ }
+ var nextState = _payload.call(instance, prevState, nextProps);
+ {
+ exitDisallowedContextReadInDEV();
+ }
+ return nextState;
+ }
+ // State object
+ return _payload;
+ }
+ case CaptureUpdate: {
+ workInProgress.effectTag =
+ (workInProgress.effectTag & ~ShouldCapture) | DidCapture;
+ }
+ // Intentional fallthrough
+ case UpdateState: {
+ var _payload2 = update.payload;
+ var partialState = void 0;
+ if (typeof _payload2 === "function") {
+ // Updater function
+ {
+ enterDisallowedContextReadInDEV();
+ if (
+ debugRenderPhaseSideEffects ||
+ (debugRenderPhaseSideEffectsForStrictMode &&
+ workInProgress.mode & StrictMode)
+ ) {
+ _payload2.call(instance, prevState, nextProps);
+ }
+ }
+ partialState = _payload2.call(instance, prevState, nextProps);
+ {
+ exitDisallowedContextReadInDEV();
+ }
+ } else {
+ // Partial state object
+ partialState = _payload2;
+ }
+ if (partialState === null || partialState === undefined) {
+ // Null and undefined are treated as no-ops.
+ return prevState;
+ }
+ // Merge the partial state and the previous state.
+ return Object.assign({}, prevState, partialState);
+ }
+ case ForceUpdate: {
+ hasForceUpdate = true;
+ return prevState;
+ }
+ }
+ return prevState;
+}
+
+function processUpdateQueue(
+ workInProgress,
+ queue,
+ props,
+ instance,
+ renderExpirationTime
+) {
+ hasForceUpdate = false;
+
+ queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);
+
+ {
+ currentlyProcessingQueue = queue;
+ }
+
+ // These values may change as we process the queue.
+ var newBaseState = queue.baseState;
+ var newFirstUpdate = null;
+ var newExpirationTime = NoWork;
+
+ // Iterate through the list of updates to compute the result.
+ var update = queue.firstUpdate;
+ var resultState = newBaseState;
+ while (update !== null) {
+ var updateExpirationTime = update.expirationTime;
+ if (updateExpirationTime < renderExpirationTime) {
+ // This update does not have sufficient priority. Skip it.
+ if (newFirstUpdate === null) {
+ // This is the first skipped update. It will be the first update in
+ // the new list.
+ newFirstUpdate = update;
+ // Since this is the first update that was skipped, the current result
+ // is the new base state.
+ newBaseState = resultState;
+ }
+ // Since this update will remain in the list, update the remaining
+ // expiration time.
+ if (newExpirationTime < updateExpirationTime) {
+ newExpirationTime = updateExpirationTime;
+ }
+ } else {
+ // This update does have sufficient priority. Process it and compute
+ // a new result.
+ resultState = getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ resultState,
+ props,
+ instance
+ );
+ var _callback = update.callback;
+ if (_callback !== null) {
+ workInProgress.effectTag |= Callback;
+ // Set this to null, in case it was mutated during an aborted render.
+ update.nextEffect = null;
+ if (queue.lastEffect === null) {
+ queue.firstEffect = queue.lastEffect = update;
+ } else {
+ queue.lastEffect.nextEffect = update;
+ queue.lastEffect = update;
+ }
+ }
+ }
+ // Continue to the next update.
+ update = update.next;
+ }
+
+ // Separately, iterate though the list of captured updates.
+ var newFirstCapturedUpdate = null;
+ update = queue.firstCapturedUpdate;
+ while (update !== null) {
+ var _updateExpirationTime = update.expirationTime;
+ if (_updateExpirationTime < renderExpirationTime) {
+ // This update does not have sufficient priority. Skip it.
+ if (newFirstCapturedUpdate === null) {
+ // This is the first skipped captured update. It will be the first
+ // update in the new list.
+ newFirstCapturedUpdate = update;
+ // If this is the first update that was skipped, the current result is
+ // the new base state.
+ if (newFirstUpdate === null) {
+ newBaseState = resultState;
+ }
}
+ // Since this update will remain in the list, update the remaining
+ // expiration time.
+ if (newExpirationTime < _updateExpirationTime) {
+ newExpirationTime = _updateExpirationTime;
+ }
+ } else {
+ // This update does have sufficient priority. Process it and compute
+ // a new result.
+ resultState = getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ resultState,
+ props,
+ instance
+ );
+ var _callback2 = update.callback;
+ if (_callback2 !== null) {
+ workInProgress.effectTag |= Callback;
+ // Set this to null, in case it was mutated during an aborted render.
+ update.nextEffect = null;
+ if (queue.lastCapturedEffect === null) {
+ queue.firstCapturedEffect = queue.lastCapturedEffect = update;
+ } else {
+ queue.lastCapturedEffect.nextEffect = update;
+ queue.lastCapturedEffect = update;
+ }
+ }
+ }
+ update = update.next;
+ }
+
+ if (newFirstUpdate === null) {
+ queue.lastUpdate = null;
+ }
+ if (newFirstCapturedUpdate === null) {
+ queue.lastCapturedUpdate = null;
+ } else {
+ workInProgress.effectTag |= Callback;
+ }
+ if (newFirstUpdate === null && newFirstCapturedUpdate === null) {
+ // We processed every update, without skipping. That means the new base
+ // state is the same as the result state.
+ newBaseState = resultState;
+ }
+
+ queue.baseState = newBaseState;
+ queue.firstUpdate = newFirstUpdate;
+ queue.firstCapturedUpdate = newFirstCapturedUpdate;
+
+ // Set the remaining expiration time to be whatever is remaining in the queue.
+ // This should be fine because the only two other things that contribute to
+ // expiration time are props and context. We're already in the middle of the
+ // begin phase by the time we start processing the queue, so we've already
+ // dealt with the props. Context in components that specify
+ // shouldComponentUpdate is tricky; but we'll have to account for
+ // that regardless.
+ workInProgress.expirationTime = newExpirationTime;
+ workInProgress.memoizedState = resultState;
+
+ {
+ currentlyProcessingQueue = null;
+ }
+}
+
+function callCallback(callback, context) {
+ invariant(
+ typeof callback === "function",
+ "Invalid argument passed as callback. Expected a function. Instead " +
+ "received: %s",
+ callback
+ );
+ callback.call(context);
+}
+
+function resetHasForceUpdateBeforeProcessing() {
+ hasForceUpdate = false;
+}
+
+function checkHasForceUpdateAfterProcessing() {
+ return hasForceUpdate;
+}
+
+function commitUpdateQueue(
+ finishedWork,
+ finishedQueue,
+ instance,
+ renderExpirationTime
+) {
+ // If the finished render included captured updates, and there are still
+ // lower priority updates left over, we need to keep the captured updates
+ // in the queue so that they are rebased and not dropped once we process the
+ // queue again at the lower priority.
+ if (finishedQueue.firstCapturedUpdate !== null) {
+ // Join the captured update list to the end of the normal list.
+ if (finishedQueue.lastUpdate !== null) {
+ finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate;
+ finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate;
+ }
+ // Clear the list of captured updates.
+ finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null;
+ }
+
+ // Commit the effects
+ commitUpdateEffects(finishedQueue.firstEffect, instance);
+ finishedQueue.firstEffect = finishedQueue.lastEffect = null;
+
+ commitUpdateEffects(finishedQueue.firstCapturedEffect, instance);
+ finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null;
+}
+
+function commitUpdateEffects(effect, instance) {
+ while (effect !== null) {
+ var _callback3 = effect.callback;
+ if (_callback3 !== null) {
+ effect.callback = null;
+ callCallback(_callback3, instance);
+ }
+ effect = effect.nextEffect;
+ }
+}
+
+function createCapturedValue(value, source) {
+ // If the value is an error, call this function immediately after it is thrown
+ // so the stack is accurate.
+ return {
+ value: value,
+ source: source,
+ stack: getStackByFiberInDevAndProd(source)
+ };
}
function markUpdate(workInProgress) {
@@ -13464,7 +14515,12 @@
var nextDidTimeout = nextState !== null;
var prevDidTimeout = current !== null && current.memoizedState !== null;
- if (current !== null && !nextDidTimeout && prevDidTimeout) {
+ if (current === null) {
+ // In cases where we didn't find a suitable hydration boundary we never
+ // downgraded this to a DehydratedSuspenseComponent, but we still need to
+ // pop the hydration state since we might be inside the insertion tree.
+ popHydrationState(workInProgress);
+ } else if (!nextDidTimeout && prevDidTimeout) {
// We just switched from the fallback to the normal children. Delete
// the fallback.
// TODO: Would it be better to store the fallback fragment on
@@ -13483,18 +14539,10 @@
}
}
- // The children either timed out after previously being visible, or
- // were restored after previously being hidden. Schedule an effect
- // to update their visiblity.
- if (
- //
- nextDidTimeout !== prevDidTimeout ||
- // Outside concurrent mode, the primary children commit in an
- // inconsistent state, even if they are hidden. So if they are hidden,
- // we need to schedule an effect to re-hide them, just in case.
- ((workInProgress.effectTag & ConcurrentMode) === NoContext &&
- nextDidTimeout)
- ) {
+ if (nextDidTimeout || prevDidTimeout) {
+ // If the children are hidden, or if they were previous hidden, schedule
+ // an effect to toggle their visibility. This is also used to attach a
+ // retry listener to the promise.
workInProgress.effectTag |= Update;
}
break;
@@ -13526,6 +14574,29 @@
}
break;
}
+ case DehydratedSuspenseComponent: {
+ if (enableSuspenseServerRenderer) {
+ if (current === null) {
+ var _wasHydrated2 = popHydrationState(workInProgress);
+ invariant(
+ _wasHydrated2,
+ "A dehydrated suspense component was completed without a hydrated node. " +
+ "This is probably a bug in React."
+ );
+ skipPastDehydratedSuspenseInstance(workInProgress);
+ } else if ((workInProgress.effectTag & DidCapture) === NoEffect) {
+ // This boundary did not suspend so it's now hydrated.
+ // To handle any future suspense cases, we're going to now upgrade it
+ // to a Suspense component. We detach it from the existing current fiber.
+ current.alternate = null;
+ workInProgress.alternate = null;
+ workInProgress.tag = SuspenseComponent;
+ workInProgress.memoizedState = null;
+ workInProgress.stateNode = null;
+ }
+ }
+ break;
+ }
default:
invariant(
false,
@@ -13537,7 +14608,7 @@
return null;
}
-function shouldCaptureSuspense(current, workInProgress) {
+function shouldCaptureSuspense(workInProgress) {
// In order to capture, the Suspense component must have a fallback prop.
if (workInProgress.memoizedProps.fallback === undefined) {
return false;
@@ -13669,6 +14740,8 @@
didWarnAboutUndefinedSnapshotBeforeUpdate = new Set();
}
+var PossiblyWeakSet$1 = typeof WeakSet === "function" ? WeakSet : Set;
+
function logError(boundary, errorInfo) {
var source = errorInfo.source;
var stack = errorInfo.stack;
@@ -13847,9 +14920,6 @@
}
function commitHookEffectList(unmountTag, mountTag, finishedWork) {
- if (!enableHooks) {
- return;
- }
var updateQueue = finishedWork.updateQueue;
var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
if (lastEffect !== null) {
@@ -13859,24 +14929,27 @@
if ((effect.tag & unmountTag) !== NoEffect$1) {
// Unmount
var destroy = effect.destroy;
- effect.destroy = null;
- if (destroy !== null) {
+ effect.destroy = undefined;
+ if (destroy !== undefined) {
destroy();
}
}
if ((effect.tag & mountTag) !== NoEffect$1) {
// Mount
var create = effect.create;
- var _destroy = create();
- if (typeof _destroy !== "function") {
+ effect.destroy = create();
+
{
- if (_destroy !== null && _destroy !== undefined) {
- warningWithoutStack$1(
- false,
- "useEffect function must return a cleanup function or " +
- "nothing.%s%s",
- typeof _destroy.then === "function"
- ? "\n\nIt looks like you wrote useEffect(async () => ...) or returned a Promise. " +
+ var _destroy = effect.destroy;
+ if (_destroy !== undefined && typeof _destroy !== "function") {
+ var addendum = void 0;
+ if (_destroy === null) {
+ addendum =
+ " You returned null. If your effect does not require clean " +
+ "up, return undefined (or nothing).";
+ } else if (typeof _destroy.then === "function") {
+ addendum =
+ "\n\nIt looks like you wrote useEffect(async () => ...) or returned a Promise. " +
"Instead, you may write an async function separately " +
"and then call it from inside the effect:\n\n" +
"async function fetchComment(commentId) {\n" +
@@ -13886,15 +14959,19 @@
" fetchComment(commentId);\n" +
"}, [commentId]);\n\n" +
"In the future, React will provide a more idiomatic solution for data fetching " +
- "that doesn't involve writing effects manually."
- : "",
+ "that doesn't involve writing effects manually.";
+ } else {
+ addendum = " You returned: " + _destroy;
+ }
+ warningWithoutStack$1(
+ false,
+ "An Effect function must not return anything besides a function, " +
+ "which is used for clean-up.%s%s",
+ addendum,
getStackByFiberInDevAndProd(finishedWork)
);
}
}
- _destroy = null;
- }
- effect.destroy = _destroy;
}
effect = effect.next;
} while (effect !== firstEffect);
@@ -14139,7 +15216,7 @@
function hideOrUnhideAllChildren(finishedWork, isHidden) {
if (supportsMutation) {
- // We only have the top Fiber that was inserted but we need recurse down its
+ // We only have the top Fiber that was inserted but we need to recurse down its
var node = finishedWork;
while (true) {
if (node.tag === HostComponent) {
@@ -14247,7 +15324,7 @@
var effect = firstEffect;
do {
var destroy = effect.destroy;
- if (destroy !== null) {
+ if (destroy !== undefined) {
safelyCallDestroy(current$$1, destroy);
}
effect = effect.next;
@@ -14421,7 +15498,11 @@
}
node.sibling.return = node.return;
node = node.sibling;
- while (node.tag !== HostComponent && node.tag !== HostText) {
+ while (
+ node.tag !== HostComponent &&
+ node.tag !== HostText &&
+ node.tag !== DehydratedSuspenseComponent
+ ) {
// If it is not host node and, we might have a host node inside it.
// Try to search down until we find one.
if (node.effectTag & Placement) {
@@ -14483,7 +15564,7 @@
}
var before = getHostSibling(finishedWork);
- // We only have the top Fiber that was inserted but we need recurse down its
+ // We only have the top Fiber that was inserted but we need to recurse down its
// children to find all the terminal nodes.
var node = finishedWork;
while (true) {
@@ -14525,7 +15606,7 @@
}
function unmountHostComponents(current$$1) {
- // We only have the top Fiber that was deleted but we need recurse down its
+ // We only have the top Fiber that was deleted but we need to recurse down its
var node = current$$1;
// Each iteration, currentParent is populated with node's host parent if not
@@ -14574,13 +15655,23 @@
removeChild(currentParent, node.stateNode);
}
// Don't visit children because we already visited them.
+ } else if (
+ enableSuspenseServerRenderer &&
+ node.tag === DehydratedSuspenseComponent
+ ) {
+ // Delete the dehydrated suspense boundary and all of its content.
+ if (currentParentIsContainer) {
+ clearSuspenseBoundaryFromContainer(currentParent, node.stateNode);
+ } else {
+ clearSuspenseBoundary(currentParent, node.stateNode);
+ }
} else if (node.tag === HostPortal) {
+ if (node.child !== null) {
// When we go into a portal, it becomes the parent to remove from.
// We will reassign it back when we pop the portal on the way up.
currentParent = node.stateNode.containerInfo;
currentParentIsContainer = true;
// Visit children because portals might contain host components.
- if (node.child !== null) {
node.child.return = node;
node = node.child;
continue;
@@ -14725,6 +15816,30 @@
if (primaryChildParent !== null) {
hideOrUnhideAllChildren(primaryChildParent, newDidTimeout);
}
+
+ // If this boundary just timed out, then it will have a set of thenables.
+ // For each thenable, attach a listener so that when it resolves, React
+ // attempts to re-render the boundary in the primary (pre-timeout) state.
+ var thenables = finishedWork.updateQueue;
+ if (thenables !== null) {
+ finishedWork.updateQueue = null;
+ var retryCache = finishedWork.stateNode;
+ if (retryCache === null) {
+ retryCache = finishedWork.stateNode = new PossiblyWeakSet$1();
+ }
+ thenables.forEach(function(thenable) {
+ // Memoize using the boundary fiber to prevent redundant listeners.
+ var retry = resolveRetryThenable.bind(null, finishedWork, thenable);
+ if (enableSchedulerTracing) {
+ retry = tracing.unstable_wrap(retry);
+ }
+ if (!retryCache.has(thenable)) {
+ retryCache.add(thenable);
+ thenable.then(retry, retry);
+ }
+ });
+ }
+
return;
}
case IncompleteClassComponent: {
@@ -14747,6 +15862,9 @@
resetTextContent(current$$1.stateNode);
}
+var PossiblyWeakSet = typeof WeakSet === "function" ? WeakSet : Set;
+var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map;
+
function createRootErrorUpdate(fiber, errorInfo, expirationTime) {
var update = createUpdate(expirationTime);
// Unmount the root by rendering null.
@@ -14810,6 +15928,39 @@
return update;
}
+function attachPingListener(root, renderExpirationTime, thenable) {
+ // Attach a listener to the promise to "ping" the root and retry. But
+ // only if one does not already exist for the current render expiration
+ // time (which acts like a "thread ID" here).
+ var pingCache = root.pingCache;
+ var threadIDs = void 0;
+ if (pingCache === null) {
+ pingCache = root.pingCache = new PossiblyWeakMap();
+ threadIDs = new Set();
+ pingCache.set(thenable, threadIDs);
+ } else {
+ threadIDs = pingCache.get(thenable);
+ if (threadIDs === undefined) {
+ threadIDs = new Set();
+ pingCache.set(thenable, threadIDs);
+ }
+ }
+ if (!threadIDs.has(renderExpirationTime)) {
+ // Memoize using the thread ID to prevent redundant listeners.
+ threadIDs.add(renderExpirationTime);
+ var ping = pingSuspendedRoot.bind(
+ null,
+ root,
+ thenable,
+ renderExpirationTime
+ );
+ if (enableSchedulerTracing) {
+ ping = tracing.unstable_wrap(ping);
+ }
+ thenable.then(ping, ping);
+ }
+}
+
function throwException(
root,
returnFiber,
@@ -14864,6 +16015,9 @@
}
}
}
+ // If there is a DehydratedSuspenseComponent we don't have to do anything because
+ // if something suspends inside it, we will simply leave that as dehydrated. It
+ // will never timeout.
_workInProgress = _workInProgress.return;
} while (_workInProgress !== null);
@@ -14872,29 +16026,19 @@
do {
if (
_workInProgress.tag === SuspenseComponent &&
- shouldCaptureSuspense(_workInProgress.alternate, _workInProgress)
+ shouldCaptureSuspense(_workInProgress)
) {
// Found the nearest boundary.
- // If the boundary is not in concurrent mode, we should not suspend, and
- // likewise, when the promise resolves, we should ping synchronously.
- var pingTime =
- (_workInProgress.mode & ConcurrentMode) === NoEffect
- ? Sync
- : renderExpirationTime;
-
- // Attach a listener to the promise to "ping" the root and retry.
- var onResolveOrReject = retrySuspendedRoot.bind(
- null,
- root,
- _workInProgress,
- sourceFiber,
- pingTime
- );
- if (enableSchedulerTracing) {
- onResolveOrReject = tracing.unstable_wrap(onResolveOrReject);
+ // Stash the promise on the boundary fiber. If the boundary times out, we'll
+ var thenables = _workInProgress.updateQueue;
+ if (thenables === null) {
+ var updateQueue = new Set();
+ updateQueue.add(thenable);
+ _workInProgress.updateQueue = updateQueue;
+ } else {
+ thenables.add(thenable);
}
- thenable.then(onResolveOrReject, onResolveOrReject);
// If the boundary is outside of concurrent mode, we should *not*
// suspend the commit. Pretend as if the suspended component rendered
@@ -14913,18 +16057,25 @@
sourceFiber.effectTag &= ~(LifecycleEffectMask | Incomplete);
if (sourceFiber.tag === ClassComponent) {
- var _current = sourceFiber.alternate;
- if (_current === null) {
+ var currentSourceFiber = sourceFiber.alternate;
+ if (currentSourceFiber === null) {
// This is a new mount. Change the tag so it's not mistaken for a
// completed class component. For example, we should not call
// componentWillUnmount if it is deleted.
sourceFiber.tag = IncompleteClassComponent;
+ } else {
+ // When we try rendering again, we should not reuse the current fiber,
+ // since it's known to be in an inconsistent state. Use a force updte to
+ // prevent a bail out.
+ var update = createUpdate(Sync);
+ update.tag = ForceUpdate;
+ enqueueUpdate(sourceFiber, update);
}
}
- // The source fiber did not complete. Mark it with the current
- // render priority to indicate that it still has pending work.
- sourceFiber.expirationTime = renderExpirationTime;
+ // The source fiber did not complete. Mark it with Sync priority to
+ // indicate that it still has pending work.
+ sourceFiber.expirationTime = Sync;
// Exit without suspending.
return;
@@ -14933,9 +16084,11 @@
// Confirmed that the boundary is in a concurrent mode tree. Continue
// with the normal suspend path.
+ attachPingListener(root, renderExpirationTime, thenable);
+
var absoluteTimeoutMs = void 0;
if (earliestTimeoutMs === -1) {
- // If no explicit threshold is given, default to an abitrarily large
+ // If no explicit threshold is given, default to an arbitrarily large
// value. The actual size doesn't matter because the threshold for the
// whole tree will be clamped to the expiration time.
absoluteTimeoutMs = maxSigned31BitInt;
@@ -14971,6 +16124,40 @@
_workInProgress.effectTag |= ShouldCapture;
_workInProgress.expirationTime = renderExpirationTime;
return;
+ } else if (
+ enableSuspenseServerRenderer &&
+ _workInProgress.tag === DehydratedSuspenseComponent
+ ) {
+ attachPingListener(root, renderExpirationTime, thenable);
+
+ // Since we already have a current fiber, we can eagerly add a retry listener.
+ var retryCache = _workInProgress.memoizedState;
+ if (retryCache === null) {
+ retryCache = _workInProgress.memoizedState = new PossiblyWeakSet();
+ var _current = _workInProgress.alternate;
+ invariant(
+ _current,
+ "A dehydrated suspense boundary must commit before trying to render. " +
+ "This is probably a bug in React."
+ );
+ _current.memoizedState = retryCache;
+ }
+ // Memoize using the boundary fiber to prevent redundant listeners.
+ if (!retryCache.has(thenable)) {
+ retryCache.add(thenable);
+ var retry = resolveRetryThenable.bind(
+ null,
+ _workInProgress,
+ thenable
+ );
+ if (enableSchedulerTracing) {
+ retry = tracing.unstable_wrap(retry);
+ }
+ thenable.then(retry, retry);
+ }
+ _workInProgress.effectTag |= ShouldCapture;
+ _workInProgress.expirationTime = renderExpirationTime;
+ return;
}
// This boundary already captured during this render. Continue to the next
// boundary.
@@ -15000,12 +16187,12 @@
var _errorInfo = value;
workInProgress.effectTag |= ShouldCapture;
workInProgress.expirationTime = renderExpirationTime;
- var update = createRootErrorUpdate(
+ var _update = createRootErrorUpdate(
workInProgress,
_errorInfo,
renderExpirationTime
);
- enqueueCapturedUpdate(workInProgress, update);
+ enqueueCapturedUpdate(workInProgress, _update);
return;
}
case ClassComponent:
@@ -15023,12 +16210,12 @@
workInProgress.effectTag |= ShouldCapture;
workInProgress.expirationTime = renderExpirationTime;
// Schedule the error boundary to re-render using updated state
- var _update = createClassErrorUpdate(
+ var _update2 = createClassErrorUpdate(
workInProgress,
errorInfo,
renderExpirationTime
);
- enqueueCapturedUpdate(workInProgress, _update);
+ enqueueCapturedUpdate(workInProgress, _update2);
return;
}
break;
@@ -15066,6 +16253,7 @@
return workInProgress;
}
case HostComponent: {
+ // TODO: popHydrationState
popHostContext(workInProgress);
return null;
}
@@ -15078,6 +16266,19 @@
}
return null;
}
+ case DehydratedSuspenseComponent: {
+ if (enableSuspenseServerRenderer) {
+ // TODO: popHydrationState
+ var _effectTag3 = workInProgress.effectTag;
+ if (_effectTag3 & ShouldCapture) {
+ workInProgress.effectTag =
+ (_effectTag3 & ~ShouldCapture) | DidCapture;
+ // Captured a suspense effect. Re-render the boundary.
+ return workInProgress;
+ }
+ }
+ return null;
+ }
case HostPortal:
popHostContainer(workInProgress);
return null;
@@ -15118,22 +16319,7 @@
}
}
-var Dispatcher = {
- readContext: readContext,
- useCallback: useCallback,
- useContext: useContext,
- useEffect: useEffect,
- useImperativeMethods: useImperativeMethods,
- useLayoutEffect: useLayoutEffect,
- useMemo: useMemo,
- useReducer: useReducer,
- useRef: useRef,
- useState: useState
-};
-var DispatcherWithoutHooks = {
- readContext: readContext
-};
-
+var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
var ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner;
var didWarnAboutStateTransition = void 0;
@@ -15206,11 +16392,6 @@
};
}
-// Represents the expiration time that incoming updates should use. (If this
-// is NoWork, use the default strategy: async updates in async mode, sync
-// updates in sync mode.)
-var expirationContext = NoWork;
-
var isWorking = false;
// The next work in progress fiber that we're currently working on.
@@ -15443,6 +16624,9 @@
}
}
while (nextEffect !== null) {
+ {
+ setCurrentFiber(nextEffect);
+ }
var effectTag = nextEffect.effectTag;
if (effectTag & (Update | Callback)) {
@@ -15461,12 +16645,15 @@
commitAttachRef(nextEffect);
}
- if (enableHooks && effectTag & Passive) {
+ if (effectTag & Passive) {
rootWithPendingPassiveEffects = finishedRoot;
}
nextEffect = nextEffect.nextEffect;
}
+ {
+ resetCurrentFiber();
+ }
}
function commitPassiveEffects(root, firstEffect) {
@@ -15480,6 +16667,10 @@
var effect = firstEffect;
do {
+ {
+ setCurrentFiber(effect);
+ }
+
if (effect.effectTag & Passive) {
var didError = false;
var error = void 0;
@@ -15496,6 +16687,9 @@
}
effect = effect.nextEffect;
} while (effect !== null);
+ {
+ resetCurrentFiber();
+ }
isRendering = previousIsRendering;
@@ -15504,6 +16698,10 @@
if (rootExpirationTime !== NoWork) {
requestWork(root, rootExpirationTime);
}
+ // Flush any sync work that was scheduled by effects
+ if (!isBatchingUpdates && !isRendering) {
+ performSyncWork();
+ }
}
function isAlreadyFailedLegacyErrorBoundary(instance) {
@@ -15522,8 +16720,10 @@
}
function flushPassiveEffects() {
+ if (passiveEffectCallbackHandle !== null) {
+ cancelPassiveEffects(passiveEffectCallbackHandle);
+ }
if (passiveEffectCallback !== null) {
- scheduler.unstable_cancelCallback(passiveEffectCallbackHandle);
// We call the scheduled callback instead of commitPassiveEffects directly
// to ensure tracing works correctly.
passiveEffectCallback();
@@ -15697,11 +16897,7 @@
}
}
- if (
- enableHooks &&
- firstEffect !== null &&
- rootWithPendingPassiveEffects !== null
- ) {
+ if (firstEffect !== null && rootWithPendingPassiveEffects !== null) {
// This commit included a passive effect. These do not need to fire until
// after the next paint. Schedule an callback to fire them in an async
// event. To ensure serial execution, the callback will be flushed early if
@@ -15713,7 +16909,12 @@
// here because that code is still in flux.
callback = tracing.unstable_wrap(callback);
}
- passiveEffectCallbackHandle = scheduler.unstable_scheduleCallback(callback);
+ passiveEffectCallbackHandle = scheduler.unstable_runWithPriority(
+ scheduler.unstable_NormalPriority,
+ function() {
+ return schedulePassiveEffects(callback);
+ }
+ );
passiveEffectCallback = callback;
}
@@ -16116,7 +17317,7 @@
}
} else {
// Flush asynchronous work until there's a higher priority event
- while (nextUnitOfWork !== null && !shouldYieldToRenderer()) {
+ while (nextUnitOfWork !== null && !shouldYield$$1()) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
}
@@ -16132,11 +17333,8 @@
flushPassiveEffects();
isWorking = true;
- if (enableHooks) {
- ReactCurrentOwner$2.currentDispatcher = Dispatcher;
- } else {
- ReactCurrentOwner$2.currentDispatcher = DispatcherWithoutHooks;
- }
+ var previousDispatcher = ReactCurrentDispatcher.current;
+ ReactCurrentDispatcher.current = ContextOnlyDispatcher;
var expirationTime = root.nextExpirationTimeToWorkOn;
@@ -16190,7 +17388,7 @@
subscriber.onWorkStarted(interactions, threadID);
} catch (error) {
// Work thrown by an interaction tracing subscriber should be rethrown,
- // But only once it's safe (to avoid leaveing the scheduler in an invalid state).
+ // But only once it's safe (to avoid leaving the scheduler in an invalid state).
// Store the error for now and we'll re-throw in finishRendering().
if (!hasUnhandledError) {
hasUnhandledError = true;
@@ -16297,7 +17495,7 @@
// We're done performing work. Time to clean up.
isWorking = false;
- ReactCurrentOwner$2.currentDispatcher = null;
+ ReactCurrentDispatcher.current = previousDispatcher;
resetContextDependences();
resetHooks();
@@ -16367,7 +17565,7 @@
return;
} else if (
// There's no lower priority work, but we're rendering asynchronously.
- // Synchronsouly attempt to render the same level one more time. This is
+ // Synchronously attempt to render the same level one more time. This is
// similar to a suspend, but without a timeout because we're not waiting
// for a promise to resolve.
!root.didError &&
@@ -16481,52 +17679,58 @@
}
function computeExpirationForFiber(currentTime, fiber) {
+ var priorityLevel = scheduler.unstable_getCurrentPriorityLevel();
+
var expirationTime = void 0;
- if (expirationContext !== NoWork) {
- // An explicit expiration context was set;
- expirationTime = expirationContext;
- } else if (isWorking) {
- if (isCommitting$1) {
- // Updates that occur during the commit phase should have sync priority
- // by default.
+ if ((fiber.mode & ConcurrentMode) === NoContext) {
+ // Outside of concurrent mode, updates are always synchronous.
expirationTime = Sync;
- } else {
- // Updates during the render phase should expire at the same time as
- // the work that is being rendered.
+ } else if (isWorking && !isCommitting$1) {
+ // During render phase, updates expire during as the current render.
expirationTime = nextRenderExpirationTime;
- }
} else {
- // No explicit expiration context was set, and we're not currently
- // performing work. Calculate a new expiration time.
- if (fiber.mode & ConcurrentMode) {
- if (isBatchingInteractiveUpdates) {
- // This is an interactive update
+ switch (priorityLevel) {
+ case scheduler.unstable_ImmediatePriority:
+ expirationTime = Sync;
+ break;
+ case scheduler.unstable_UserBlockingPriority:
expirationTime = computeInteractiveExpiration(currentTime);
- } else {
- // This is an async update
+ break;
+ case scheduler.unstable_NormalPriority:
+ // This is a normal, concurrent update
expirationTime = computeAsyncExpiration(currentTime);
+ break;
+ case scheduler.unstable_LowPriority:
+ case scheduler.unstable_IdlePriority:
+ expirationTime = Never;
+ break;
+ default:
+ invariant(
+ false,
+ "Unknown priority level. This error is likely caused by a bug in " +
+ "React. Please file an issue."
+ );
}
+
// If we're in the middle of rendering a tree, do not update at the same
// expiration time that is already rendering.
if (nextRoot !== null && expirationTime === nextRenderExpirationTime) {
expirationTime -= 1;
}
- } else {
- // This is a sync update
- expirationTime = Sync;
- }
}
- if (isBatchingInteractiveUpdates) {
- // This is an interactive update. Keep track of the lowest pending
- // interactive expiration time. This allows us to synchronously flush
- // all interactive updates when needed.
- if (
- lowestPriorityPendingInteractiveExpirationTime === NoWork ||
- expirationTime < lowestPriorityPendingInteractiveExpirationTime
+
+ // Keep track of the lowest pending interactive expiration time. This
+ // allows us to synchronously flush all interactive updates
+ // when needed.
+ // TODO: Move this to renderer?
+ if (
+ priorityLevel === scheduler.unstable_UserBlockingPriority &&
+ (lowestPriorityPendingInteractiveExpirationTime === NoWork ||
+ expirationTime < lowestPriorityPendingInteractiveExpirationTime)
) {
lowestPriorityPendingInteractiveExpirationTime = expirationTime;
}
- }
+
return expirationTime;
}
@@ -16544,57 +17748,77 @@
nextRenderDidError = true;
}
-function retrySuspendedRoot(root, boundaryFiber, sourceFiber, suspendedTime) {
- var retryTime = void 0;
-
- if (isPriorityLevelSuspended(root, suspendedTime)) {
- // Ping at the original level
- retryTime = suspendedTime;
-
- markPingedPriorityLevel(root, retryTime);
- } else {
- // Suspense already timed out. Compute a new expiration time
- var currentTime = requestCurrentTime();
- retryTime = computeExpirationForFiber(currentTime, boundaryFiber);
- markPendingPriorityLevel(root, retryTime);
+function pingSuspendedRoot(root, thenable, pingTime) {
+ // A promise that previously suspended React from committing has resolved.
+ // If React is still suspended, try again at the previous level (pingTime).
+
+ var pingCache = root.pingCache;
+ if (pingCache !== null) {
+ // The thenable resolved, so we no longer need to memoize, because it will
+ // never be thrown again.
+ pingCache.delete(thenable);
}
- // TODO: If the suspense fiber has already rendered the primary children
- // without suspending (that is, all of the promises have already resolved),
- // we should not trigger another update here. One case this happens is when
- // we are in sync mode and a single promise is thrown both on initial render
- // and on update; we attach two .then(retrySuspendedRoot) callbacks and each
- // one performs Sync work, rerendering the Suspense.
-
- if ((boundaryFiber.mode & ConcurrentMode) !== NoContext) {
- if (root === nextRoot && nextRenderExpirationTime === suspendedTime) {
+ if (nextRoot !== null && nextRenderExpirationTime === pingTime) {
// Received a ping at the same priority level at which we're currently
// rendering. Restart from the root.
nextRoot = null;
+ } else {
+ // Confirm that the root is still suspended at this level. Otherwise exit.
+ if (isPriorityLevelSuspended(root, pingTime)) {
+ // Ping at the original level
+ markPingedPriorityLevel(root, pingTime);
+ var rootExpirationTime = root.expirationTime;
+ if (rootExpirationTime !== NoWork) {
+ requestWork(root, rootExpirationTime);
}
}
-
- scheduleWorkToRoot(boundaryFiber, retryTime);
- if ((boundaryFiber.mode & ConcurrentMode) === NoContext) {
- // Outside of concurrent mode, we must schedule an update on the source
- // fiber, too, since it already committed in an inconsistent state and
- // therefore does not have any pending work.
- scheduleWorkToRoot(sourceFiber, retryTime);
- var sourceTag = sourceFiber.tag;
- if (sourceTag === ClassComponent && sourceFiber.stateNode !== null) {
- // When we try rendering again, we should not reuse the current fiber,
- // since it's known to be in an inconsistent state. Use a force updte to
- // prevent a bail out.
- var update = createUpdate(retryTime);
- update.tag = ForceUpdate;
- enqueueUpdate(sourceFiber, update);
- }
}
+}
+function retryTimedOutBoundary(boundaryFiber) {
+ var currentTime = requestCurrentTime();
+ var retryTime = computeExpirationForFiber(currentTime, boundaryFiber);
+ var root = scheduleWorkToRoot(boundaryFiber, retryTime);
+ if (root !== null) {
+ markPendingPriorityLevel(root, retryTime);
var rootExpirationTime = root.expirationTime;
if (rootExpirationTime !== NoWork) {
requestWork(root, rootExpirationTime);
}
+ }
+}
+
+function resolveRetryThenable(boundaryFiber, thenable) {
+ // The boundary fiber (a Suspense component) previously timed out and was
+ // rendered in its fallback state. One of the promises that suspended it has
+ // resolved, which means at least part of the tree was likely unblocked. Try
+ var retryCache = void 0;
+ if (enableSuspenseServerRenderer) {
+ switch (boundaryFiber.tag) {
+ case SuspenseComponent:
+ retryCache = boundaryFiber.stateNode;
+ break;
+ case DehydratedSuspenseComponent:
+ retryCache = boundaryFiber.memoizedState;
+ break;
+ default:
+ invariant(
+ false,
+ "Pinged unknown suspense boundary type. " +
+ "This is probably a bug in React."
+ );
+ }
+ } else {
+ retryCache = boundaryFiber.stateNode;
+ }
+ if (retryCache !== null) {
+ // The thenable resolved, so we no longer need to memoize, because it will
+ // never be thrown again.
+ retryCache.delete(thenable);
+ }
+
+ retryTimedOutBoundary(boundaryFiber);
}
function scheduleWorkToRoot(fiber, expirationTime) {
@@ -16683,6 +17907,27 @@
return root;
}
+function warnIfNotCurrentlyBatchingInDev(fiber) {
+ {
+ if (isRendering === false && isBatchingUpdates === false) {
+ warningWithoutStack$1(
+ false,
+ "An update to %s inside a test was not wrapped in act(...).\n\n" +
+ "When testing, code that causes React state updates should be wrapped into act(...):\n\n" +
+ "act(() => {\n" +
+ " /* fire events that update state */\n" +
+ "});\n" +
+ "/* assert on the output */\n\n" +
+ "This ensures that you're testing the behavior the user would see in the browser." +
+ " Learn more at https://fb.me/react-wrap-tests-with-act" +
+ "%s",
+ getComponentName(fiber.type),
+ getStackByFiberInDevAndProd(fiber)
+ );
+ }
+ }
+}
+
function scheduleWork(fiber, expirationTime) {
var root = scheduleWorkToRoot(fiber, expirationTime);
if (root === null) {
@@ -16754,7 +17999,6 @@
var isBatchingUpdates = false;
var isUnbatchingUpdates = false;
-var isBatchingInteractiveUpdates = false;
var completedBatches = null;
@@ -16820,7 +18064,7 @@
msUntilTimeout
) {
root.expirationTime = rootExpirationTime;
- if (msUntilTimeout === 0 && !shouldYieldToRenderer()) {
+ if (msUntilTimeout === 0 && !shouldYield$$1()) {
// Don't wait an additional tick. Commit the tree immediately.
root.pendingCommitExpirationTime = suspendedExpirationTime;
root.finishedWork = finishedWork;
@@ -17017,24 +18261,8 @@
nextFlushedExpirationTime = highestPriorityWork;
}
-// TODO: This wrapper exists because many of the older tests (the ones that use
-// flushDeferredPri) rely on the number of times `shouldYield` is called. We
-// should get rid of it.
-var didYield = false;
-function shouldYieldToRenderer() {
- if (didYield) {
- return true;
- }
- if (shouldYield$$1()) {
- didYield = true;
- return true;
- }
- return false;
-}
-
-function performAsyncWork() {
- try {
- if (!shouldYieldToRenderer()) {
+function performAsyncWork(didTimeout) {
+ if (didTimeout) {
// The callback timed out. That means at least one update has expired.
// Iterate through the root schedule. If they contain expired work, set
// the next render expiration time to the current time. This has the effect
@@ -17051,9 +18279,6 @@
}
}
performWork(NoWork, true);
- } finally {
- didYield = false;
- }
}
function performSyncWork() {
@@ -17079,7 +18304,7 @@
nextFlushedRoot !== null &&
nextFlushedExpirationTime !== NoWork &&
minExpirationTime <= nextFlushedExpirationTime &&
- !(didYield && currentRendererTime > nextFlushedExpirationTime)
+ !(shouldYield$$1() && currentRendererTime > nextFlushedExpirationTime)
) {
performWorkOnRoot(
nextFlushedRoot,
@@ -17223,7 +18448,7 @@
if (_finishedWork !== null) {
// We've completed the root. Check the if we should yield one more time
// before committing.
- if (!shouldYieldToRenderer()) {
+ if (!shouldYield$$1()) {
// Still time left. Commit the root.
completeRoot(root, _finishedWork, expirationTime);
} else {
@@ -17270,7 +18495,12 @@
lastCommittedRootDuringThisBatch = root;
nestedUpdateCount = 0;
}
+ scheduler.unstable_runWithPriority(
+ scheduler.unstable_ImmediatePriority,
+ function() {
commitRoot(root, finishedWork);
+ }
+ );
}
function onUncaughtError(error) {
@@ -17304,9 +18534,6 @@
}
function interactiveUpdates$1(fn, a, b) {
- if (isBatchingInteractiveUpdates) {
- return fn(a, b);
- }
// If there are any pending interactive updates, synchronously flush them.
// This needs to happen before we read any handlers, because the effect of
// the previous event may influence which handlers are called during
@@ -17320,14 +18547,16 @@
performWork(lowestPriorityPendingInteractiveExpirationTime, false);
lowestPriorityPendingInteractiveExpirationTime = NoWork;
}
- var previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates;
var previousIsBatchingUpdates = isBatchingUpdates;
- isBatchingInteractiveUpdates = true;
isBatchingUpdates = true;
try {
+ return scheduler.unstable_runWithPriority(
+ scheduler.unstable_UserBlockingPriority,
+ function() {
return fn(a, b);
+ }
+ );
} finally {
- isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates;
isBatchingUpdates = previousIsBatchingUpdates;
if (!isBatchingUpdates && !isRendering) {
performSyncWork();
@@ -17555,11 +18784,43 @@
}
}
+var overrideProps = null;
+
+{
+ var copyWithSetImpl = function(obj, path, idx, value) {
+ if (idx >= path.length) {
+ return value;
+ }
+ var key = path[idx];
+ var updated = Array.isArray(obj) ? obj.slice() : Object.assign({}, obj);
+ // $FlowFixMe number or string is fine here
+ updated[key] = copyWithSetImpl(obj[key], path, idx + 1, value);
+ return updated;
+ };
+
+ var copyWithSet = function(obj, path, value) {
+ return copyWithSetImpl(obj, path, 0, value);
+ };
+
+ // Support DevTools props for function components, forwardRef, memo, host components, etc.
+ overrideProps = function(fiber, path, value) {
+ flushPassiveEffects();
+ fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value);
+ if (fiber.alternate) {
+ fiber.alternate.pendingProps = fiber.pendingProps;
+ }
+ scheduleWork(fiber, Sync);
+ };
+}
+
function injectIntoDevTools(devToolsConfig) {
var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance;
+ var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
return injectInternals(
Object.assign({}, devToolsConfig, {
+ overrideProps: overrideProps,
+ currentDispatcherRef: ReactCurrentDispatcher,
findHostInstanceByFiber: function(fiber) {
var hostFiber = findCurrentHostFiber(fiber);
if (hostFiber === null) {
@@ -17602,7 +18863,7 @@
// TODO: this is special because it gets imported during build.
-var ReactVersion = "16.6.1";
+var ReactVersion = "16.8.3";
// Modules provided by RN:
var NativeMethodsMixin = function(findNodeHandle, findHostInstance) {
@@ -17696,6 +18957,17 @@
* Manipulation](docs/direct-manipulation.html)).
*/
setNativeProps: function(nativeProps) {
+ {
+ if (warnAboutDeprecatedSetNativeProps) {
+ warningWithoutStack$1(
+ false,
+ "Warning: Calling ref.setNativeProps(nativeProps) " +
+ "is deprecated and will be removed in a future release. " +
+ "Use the setNativeProps export from the react-native package instead." +
+ "\n\timport {setNativeProps} from 'react-native';\n\tsetNativeProps(ref, nativeProps);\n"
+ );
+ }
+ }
// Class components don't have viewConfig -> validateAttributes.
// Nor does it make sense to set native props on a non-native component.
// Instead, find the nearest host component and set props on it.
@@ -17717,7 +18989,10 @@
return;
}
- var viewConfig = maybeInstance.viewConfig;
+ var nativeTag =
+ maybeInstance._nativeTag || maybeInstance.canonical._nativeTag;
+ var viewConfig =
+ maybeInstance.viewConfig || maybeInstance.canonical.viewConfig;
{
warnForStyleProps(nativeProps, viewConfig.validAttributes);
@@ -17730,7 +19005,7 @@
// view invalidation for certain components (eg RCTTextInput) on iOS.
if (updatePayload != null) {
UIManager.updateView(
- maybeInstance._nativeTag,
+ nativeTag,
viewConfig.uiViewClassName,
updatePayload
);
@@ -17951,6 +19226,18 @@
ReactNativeComponent.prototype.setNativeProps = function setNativeProps(
nativeProps
) {
+ {
+ if (warnAboutDeprecatedSetNativeProps) {
+ warningWithoutStack$1(
+ false,
+ "Warning: Calling ref.setNativeProps(nativeProps) " +
+ "is deprecated and will be removed in a future release. " +
+ "Use the setNativeProps export from the react-native package instead." +
+ "\n\timport {setNativeProps} from 'react-native';\n\tsetNativeProps(ref, nativeProps);\n"
+ );
+ }
+ }
+
// Class components don't have viewConfig -> validateAttributes.
// Nor does it make sense to set native props on a non-native component.
// Instead, find the nearest host component and set props on it.
@@ -17972,6 +19259,8 @@
return;
}
+ var nativeTag =
+ maybeInstance._nativeTag || maybeInstance.canonical._nativeTag;
var viewConfig =
maybeInstance.viewConfig || maybeInstance.canonical.viewConfig;
@@ -17982,7 +19271,7 @@
// view invalidation for certain components (eg RCTTextInput) on iOS.
if (updatePayload != null) {
UIManager.updateView(
- maybeInstance._nativeTag,
+ nativeTag,
viewConfig.uiViewClassName,
updatePayload
);
@@ -18104,6 +19393,36 @@
};
}
+// Module provided by RN:
+function setNativeProps(handle, nativeProps) {
+ if (handle._nativeTag == null) {
+ !(handle._nativeTag != null)
+ ? warningWithoutStack$1(
+ false,
+ "setNativeProps was called with a ref that isn't a " +
+ "native component. Use React.forwardRef to get access to the underlying native component"
+ )
+ : void 0;
+ return;
+ }
+
+ {
+ warnForStyleProps(nativeProps, handle.viewConfig.validAttributes);
+ }
+
+ var updatePayload = create(nativeProps, handle.viewConfig.validAttributes);
+ // Avoid the overhead of bridge calls if there's no update.
+ // This is an expensive no-op for Android, and causes an unnecessary
+ // view invalidation for certain components (eg RCTTextInput) on iOS.
+ if (updatePayload != null) {
+ UIManager.updateView(
+ handle._nativeTag,
+ handle.viewConfig.uiViewClassName,
+ updatePayload
+ );
+ }
+}
+
// TODO: direct imports like some-package/src/* are bad. Fix me.
// Module provided by RN:
var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
@@ -18179,6 +19498,8 @@
findNodeHandle: findNodeHandle,
+ setNativeProps: setNativeProps,
+
render: function(element, containerTag, callback) {
var root = roots.get(containerTag);