From 98164cb40c87fffb2a4ee20bb25709d0319b2aa9 Mon Sep 17 00:00:00 2001 From: acdlite Date: Tue, 22 Aug 2023 15:27:20 +0000 Subject: [PATCH] Fix: Stylesheet in error UI suspends indefinitely (#27265) This fixes the regression test added in the previous commit. The "Suspensey commit" implementation relies on the `shouldRemainOnPreviousScreen` function to determine whether to 1) suspend the commit 2) activate a parent fallback and schedule a retry. The issue was that we were sometimes attempting option 2 even when there was no parent fallback. Part of the reason this bug landed is due to how `throwException` is structured. In the case of Suspensey commits, we pass a special "noop" thenable to `throwException` as a way to trigger the Suspense path. This special thenable must never have a listener attached to it. This is not a great way to structure the logic, it's just a consequence of how the code evolved over time. We should refactor it into multiple functions so we can trigger a fallback directly without having to check the type. In the meantime, I added an internal warning to help detect similar mistakes in the future. DiffTrain build for commit https://github.com/facebook/react/commit/dd480ef923930c8906a02664b01bcdea50707b5d. --- .../cjs/ReactTestRenderer-dev.js | 95 +++++++++++-------- .../cjs/ReactTestRenderer-prod.js | 59 ++++++------ .../cjs/ReactTestRenderer-profiling.js | 59 ++++++------ .../RKJSModules/vendor/react/cjs/React-dev.js | 2 +- .../vendor/react/cjs/React-prod.js | 2 +- .../vendor/react/cjs/React-profiling.js | 2 +- .../Libraries/Renderer/REVISION | 2 +- .../implementations/ReactFabric-dev.fb.js | 95 +++++++++++-------- .../implementations/ReactFabric-prod.fb.js | 59 ++++++------ .../ReactFabric-profiling.fb.js | 59 ++++++------ .../ReactNativeRenderer-dev.fb.js | 95 +++++++++++-------- .../ReactNativeRenderer-prod.fb.js | 59 ++++++------ .../ReactNativeRenderer-profiling.fb.js | 59 ++++++------ 13 files changed, 331 insertions(+), 316 deletions(-) diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js index 916d283494..fbe6a953c1 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<> */ 'use strict'; @@ -4071,7 +4071,14 @@ var SuspenseyCommitException = new Error( // for now this will do. var noopSuspenseyCommitThenable = { - then: function () {} + then: function () { + { + error( + "Internal React error: A listener was unexpectedly attached to a " + + '"noop" thenable. This is a bug in React. Please file an issue.' + ); + } + } }; function createThenableState() { // The ThenableState is created the first time a component suspends. If it @@ -11072,10 +11079,16 @@ function throwException( suspenseBoundary.updateQueue = new Set([wakeable]); } else { retryQueue.add(wakeable); + } // We only attach ping listeners in concurrent mode. Legacy + // Suspense always commits fallbacks synchronously, so there are + // no pings. + + if (suspenseBoundary.mode & ConcurrentMode) { + attachPingListener(root, wakeable, rootRenderLanes); } } - break; + return; } case OffscreenComponent: { @@ -11106,28 +11119,21 @@ function throwException( _retryQueue.add(wakeable); } } + + attachPingListener(root, wakeable, rootRenderLanes); } - break; - } // Fall through + return; + } } - - default: { - throw new Error( - "Unexpected Suspense handler tag (" + - suspenseBoundary.tag + - "). This " + - "is a bug in React." - ); - } - } // We only attach ping listeners in concurrent mode. Legacy Suspense always - // commits fallbacks synchronously, so there are no pings. - - if (suspenseBoundary.mode & ConcurrentMode) { - attachPingListener(root, wakeable, rootRenderLanes); } - return; + throw new Error( + "Unexpected Suspense handler tag (" + + suspenseBoundary.tag + + "). This " + + "is a bug in React." + ); } else { // No boundary was found. Unless this is a sync update, this is OK. // We can suspend and wait for more data to arrive. @@ -20983,9 +20989,19 @@ function shouldRemainOnPreviousScreen() { // on the previous screen, versus showing a fallback as soon as possible. It // takes into account both the priority of render and also whether showing a // fallback would produce a desirable user experience. - // TODO: Once `use` has fully replaced the `throw promise` pattern, we should + var handler = getSuspenseHandler(); + + if (handler === null) { + // There's no Suspense boundary that can provide a fallback. We have no + // choice but to remain on the previous screen. + // NOTE: We do this even for sync updates, for lack of any better option. In + // the future, we may change how we handle this, like by putting the whole + // root into a "detached" mode. + return true; + } // TODO: Once `use` has fully replaced the `throw promise` pattern, we should // be able to remove the equivalent check in finishConcurrentRender, and rely // just on this one. + if (includesOnlyTransitions(workInProgressRootRenderLanes)) { if (getShellBoundary() === null) { // We're rendering inside the "shell" of the app. Activating the nearest @@ -21001,26 +21017,21 @@ function shouldRemainOnPreviousScreen() { } } - var handler = getSuspenseHandler(); - - if (handler === null); - else { - if ( - includesOnlyRetries(workInProgressRootRenderLanes) || // In this context, an OffscreenLane counts as a Retry - // TODO: It's become increasingly clear that Retries and Offscreen are - // deeply connected. They probably can be unified further. - includesSomeLane(workInProgressRootRenderLanes, OffscreenLane) - ) { - // During a retry, we can suspend rendering if the nearest Suspense boundary - // is the boundary of the "shell", because we're guaranteed not to block - // any new content from appearing. - // - // The reason we must check if this is a retry is because it guarantees - // that suspending the work loop won't block an actual update, because - // retries don't "update" anything; they fill in fallbacks that were left - // behind by a previous transition. - return handler === getShellBoundary(); - } + if ( + includesOnlyRetries(workInProgressRootRenderLanes) || // In this context, an OffscreenLane counts as a Retry + // TODO: It's become increasingly clear that Retries and Offscreen are + // deeply connected. They probably can be unified further. + includesSomeLane(workInProgressRootRenderLanes, OffscreenLane) + ) { + // During a retry, we can suspend rendering if the nearest Suspense boundary + // is the boundary of the "shell", because we're guaranteed not to block + // any new content from appearing. + // + // The reason we must check if this is a retry is because it guarantees + // that suspending the work loop won't block an actual update, because + // retries don't "update" anything; they fill in fallbacks that were left + // behind by a previous transition. + return handler === getShellBoundary(); } // For all other Lanes besides Transitions and Retries, we should not wait // for the data to load. @@ -23966,7 +23977,7 @@ function createFiberRoot( return root; } -var ReactVersion = "18.3.0-canary-e76a5aca7-20230822"; +var ReactVersion = "18.3.0-canary-dd480ef92-20230822"; // Might add PROFILE later. diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-prod.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-prod.js index 9950d7f03e..4139951b32 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-prod.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-prod.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<855c2a9f51c40c6c16565d44997b08cb>> + * @generated SignedSource<<433e051293b336d0e7452d6c87975a14>> */ "use strict"; @@ -6731,23 +6731,20 @@ function handleThrow(root, thrownValue) { ReactCurrentOwner.current = null; thrownValue === SuspenseException ? ((thrownValue = getSuspendedThenable()), - (workInProgressRootRenderLanes & 8388480) === - workInProgressRootRenderLanes - ? (root = null === shellBoundary ? !0 : !1) - : ((root = suspenseHandlerStackCursor.current), - (root = - null === root || - ((workInProgressRootRenderLanes & 125829120) !== - workInProgressRootRenderLanes && - 0 === (workInProgressRootRenderLanes & 1073741824)) - ? !1 - : root === shellBoundary)), + (root = suspenseHandlerStackCursor.current), (workInProgressSuspendedReason = - root && - 0 === (workInProgressRootSkippedLanes & 268435455) && - 0 === (workInProgressRootInterleavedUpdatedLanes & 268435455) - ? 2 - : 3)) + (null !== root && + ((workInProgressRootRenderLanes & 8388480) === + workInProgressRootRenderLanes + ? null !== shellBoundary + : ((workInProgressRootRenderLanes & 125829120) !== + workInProgressRootRenderLanes && + 0 === (workInProgressRootRenderLanes & 1073741824)) || + root !== shellBoundary)) || + 0 !== (workInProgressRootSkippedLanes & 268435455) || + 0 !== (workInProgressRootInterleavedUpdatedLanes & 268435455) + ? 3 + : 2)) : thrownValue === SuspenseyCommitException ? ((thrownValue = getSuspendedThenable()), (workInProgressSuspendedReason = 4)) @@ -7074,8 +7071,10 @@ function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { null === retryQueue ? (suspenseBoundary.updateQueue = new Set([wakeable])) : retryQueue.add(wakeable); + suspenseBoundary.mode & 1 && + attachPingListener(root, wakeable, thrownValue); } - break; + break a; case 22: if (suspenseBoundary.mode & 1) { suspenseBoundary.flags |= 65536; @@ -7096,20 +7095,18 @@ function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { ? (offscreenQueue.retryQueue = new Set([wakeable])) : retryQueue$29.add(wakeable); } + attachPingListener(root, wakeable, thrownValue); } - break; + break a; } - default: - throw Error( - "Unexpected Suspense handler tag (" + - suspenseBoundary.tag + - "). This is a bug in React." - ); } - suspenseBoundary.mode & 1 && - attachPingListener(root, wakeable, thrownValue); - break a; - } else if (1 === root.tag) { + throw Error( + "Unexpected Suspense handler tag (" + + suspenseBoundary.tag + + "). This is a bug in React." + ); + } + if (1 === root.tag) { attachPingListener(root, wakeable, thrownValue); renderDidSuspendDelayIfPossible(); break a; @@ -8615,7 +8612,7 @@ var devToolsConfig$jscomp$inline_1029 = { throw Error("TestRenderer does not support findFiberByHostInstance()"); }, bundleType: 0, - version: "18.3.0-canary-e76a5aca7-20230822", + version: "18.3.0-canary-dd480ef92-20230822", rendererPackageName: "react-test-renderer" }; var internals$jscomp$inline_1228 = { @@ -8646,7 +8643,7 @@ var internals$jscomp$inline_1228 = { scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-canary-e76a5aca7-20230822" + reconcilerVersion: "18.3.0-canary-dd480ef92-20230822" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_1229 = __REACT_DEVTOOLS_GLOBAL_HOOK__; diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-profiling.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-profiling.js index 5bdef2dac4..ea6608eb61 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-profiling.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-profiling.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<> */ "use strict"; @@ -7071,23 +7071,20 @@ function handleThrow(root, thrownValue) { ReactCurrentOwner.current = null; thrownValue === SuspenseException ? ((thrownValue = getSuspendedThenable()), - (workInProgressRootRenderLanes & 8388480) === - workInProgressRootRenderLanes - ? (root = null === shellBoundary ? !0 : !1) - : ((root = suspenseHandlerStackCursor.current), - (root = - null === root || - ((workInProgressRootRenderLanes & 125829120) !== - workInProgressRootRenderLanes && - 0 === (workInProgressRootRenderLanes & 1073741824)) - ? !1 - : root === shellBoundary)), + (root = suspenseHandlerStackCursor.current), (workInProgressSuspendedReason = - root && - 0 === (workInProgressRootSkippedLanes & 268435455) && - 0 === (workInProgressRootInterleavedUpdatedLanes & 268435455) - ? 2 - : 3)) + (null !== root && + ((workInProgressRootRenderLanes & 8388480) === + workInProgressRootRenderLanes + ? null !== shellBoundary + : ((workInProgressRootRenderLanes & 125829120) !== + workInProgressRootRenderLanes && + 0 === (workInProgressRootRenderLanes & 1073741824)) || + root !== shellBoundary)) || + 0 !== (workInProgressRootSkippedLanes & 268435455) || + 0 !== (workInProgressRootInterleavedUpdatedLanes & 268435455) + ? 3 + : 2)) : thrownValue === SuspenseyCommitException ? ((thrownValue = getSuspendedThenable()), (workInProgressSuspendedReason = 4)) @@ -7426,8 +7423,10 @@ function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { null === retryQueue ? (suspenseBoundary.updateQueue = new Set([wakeable])) : retryQueue.add(wakeable); + suspenseBoundary.mode & 1 && + attachPingListener(root, wakeable, thrownValue); } - break; + break a; case 22: if (suspenseBoundary.mode & 1) { suspenseBoundary.flags |= 65536; @@ -7448,20 +7447,18 @@ function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { ? (offscreenQueue.retryQueue = new Set([wakeable])) : retryQueue$29.add(wakeable); } + attachPingListener(root, wakeable, thrownValue); } - break; + break a; } - default: - throw Error( - "Unexpected Suspense handler tag (" + - suspenseBoundary.tag + - "). This is a bug in React." - ); } - suspenseBoundary.mode & 1 && - attachPingListener(root, wakeable, thrownValue); - break a; - } else if (1 === root.tag) { + throw Error( + "Unexpected Suspense handler tag (" + + suspenseBoundary.tag + + "). This is a bug in React." + ); + } + if (1 === root.tag) { attachPingListener(root, wakeable, thrownValue); renderDidSuspendDelayIfPossible(); break a; @@ -9041,7 +9038,7 @@ var devToolsConfig$jscomp$inline_1071 = { throw Error("TestRenderer does not support findFiberByHostInstance()"); }, bundleType: 0, - version: "18.3.0-canary-e76a5aca7-20230822", + version: "18.3.0-canary-dd480ef92-20230822", rendererPackageName: "react-test-renderer" }; var internals$jscomp$inline_1269 = { @@ -9072,7 +9069,7 @@ var internals$jscomp$inline_1269 = { scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-canary-e76a5aca7-20230822" + reconcilerVersion: "18.3.0-canary-dd480ef92-20230822" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_1270 = __REACT_DEVTOOLS_GLOBAL_HOOK__; diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-dev.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-dev.js index 21459d3baf..46ffe2f649 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-dev.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-dev.js @@ -27,7 +27,7 @@ if ( } "use strict"; -var ReactVersion = "18.3.0-canary-e76a5aca7-20230822"; +var ReactVersion = "18.3.0-canary-dd480ef92-20230822"; // ATTENTION // When adding new symbols to this file, diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-prod.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-prod.js index 7eb6664daf..c03fef6c26 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-prod.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-prod.js @@ -616,4 +616,4 @@ exports.useSyncExternalStore = function ( exports.useTransition = function () { return ReactCurrentDispatcher.current.useTransition(); }; -exports.version = "18.3.0-canary-e76a5aca7-20230822"; +exports.version = "18.3.0-canary-dd480ef92-20230822"; diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-profiling.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-profiling.js index c10199bc74..4ce339bac5 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-profiling.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-profiling.js @@ -619,7 +619,7 @@ exports.useSyncExternalStore = function ( exports.useTransition = function () { return ReactCurrentDispatcher.current.useTransition(); }; -exports.version = "18.3.0-canary-e76a5aca7-20230822"; +exports.version = "18.3.0-canary-dd480ef92-20230822"; /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ if ( diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION index 49556ff76b..ea03e4b15b 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION @@ -1 +1 @@ -e76a5aca781abdc237f044131790ea615b500532 +dd480ef923930c8906a02664b01bcdea50707b5d diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-dev.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-dev.fb.js index 307f385324..ce97f16f80 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-dev.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-dev.fb.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<275858edcfc5ae0f3e1651eeaaeca34f>> + * @generated SignedSource<<75239e23e920b7033825cf9cc46cee37>> */ 'use strict'; @@ -7790,7 +7790,14 @@ var SuspenseyCommitException = new Error( // for now this will do. var noopSuspenseyCommitThenable = { - then: function () {} + then: function () { + { + error( + "Internal React error: A listener was unexpectedly attached to a " + + '"noop" thenable. This is a bug in React. Please file an issue.' + ); + } + } }; function createThenableState() { // The ThenableState is created the first time a component suspends. If it @@ -14959,10 +14966,16 @@ function throwException( suspenseBoundary.updateQueue = new Set([wakeable]); } else { retryQueue.add(wakeable); + } // We only attach ping listeners in concurrent mode. Legacy + // Suspense always commits fallbacks synchronously, so there are + // no pings. + + if (suspenseBoundary.mode & ConcurrentMode) { + attachPingListener(root, wakeable, rootRenderLanes); } } - break; + return; } case OffscreenComponent: { @@ -14993,28 +15006,21 @@ function throwException( _retryQueue.add(wakeable); } } + + attachPingListener(root, wakeable, rootRenderLanes); } - break; - } // Fall through + return; + } } - - default: { - throw new Error( - "Unexpected Suspense handler tag (" + - suspenseBoundary.tag + - "). This " + - "is a bug in React." - ); - } - } // We only attach ping listeners in concurrent mode. Legacy Suspense always - // commits fallbacks synchronously, so there are no pings. - - if (suspenseBoundary.mode & ConcurrentMode) { - attachPingListener(root, wakeable, rootRenderLanes); } - return; + throw new Error( + "Unexpected Suspense handler tag (" + + suspenseBoundary.tag + + "). This " + + "is a bug in React." + ); } else { // No boundary was found. Unless this is a sync update, this is OK. // We can suspend and wait for more data to arrive. @@ -23848,9 +23854,19 @@ function shouldRemainOnPreviousScreen() { // on the previous screen, versus showing a fallback as soon as possible. It // takes into account both the priority of render and also whether showing a // fallback would produce a desirable user experience. - // TODO: Once `use` has fully replaced the `throw promise` pattern, we should + var handler = getSuspenseHandler(); + + if (handler === null) { + // There's no Suspense boundary that can provide a fallback. We have no + // choice but to remain on the previous screen. + // NOTE: We do this even for sync updates, for lack of any better option. In + // the future, we may change how we handle this, like by putting the whole + // root into a "detached" mode. + return true; + } // TODO: Once `use` has fully replaced the `throw promise` pattern, we should // be able to remove the equivalent check in finishConcurrentRender, and rely // just on this one. + if (includesOnlyTransitions(workInProgressRootRenderLanes)) { if (getShellBoundary() === null) { // We're rendering inside the "shell" of the app. Activating the nearest @@ -23866,26 +23882,21 @@ function shouldRemainOnPreviousScreen() { } } - var handler = getSuspenseHandler(); - - if (handler === null); - else { - if ( - includesOnlyRetries(workInProgressRootRenderLanes) || // In this context, an OffscreenLane counts as a Retry - // TODO: It's become increasingly clear that Retries and Offscreen are - // deeply connected. They probably can be unified further. - includesSomeLane(workInProgressRootRenderLanes, OffscreenLane) - ) { - // During a retry, we can suspend rendering if the nearest Suspense boundary - // is the boundary of the "shell", because we're guaranteed not to block - // any new content from appearing. - // - // The reason we must check if this is a retry is because it guarantees - // that suspending the work loop won't block an actual update, because - // retries don't "update" anything; they fill in fallbacks that were left - // behind by a previous transition. - return handler === getShellBoundary(); - } + if ( + includesOnlyRetries(workInProgressRootRenderLanes) || // In this context, an OffscreenLane counts as a Retry + // TODO: It's become increasingly clear that Retries and Offscreen are + // deeply connected. They probably can be unified further. + includesSomeLane(workInProgressRootRenderLanes, OffscreenLane) + ) { + // During a retry, we can suspend rendering if the nearest Suspense boundary + // is the boundary of the "shell", because we're guaranteed not to block + // any new content from appearing. + // + // The reason we must check if this is a retry is because it guarantees + // that suspending the work loop won't block an actual update, because + // retries don't "update" anything; they fill in fallbacks that were left + // behind by a previous transition. + return handler === getShellBoundary(); } // For all other Lanes besides Transitions and Retries, we should not wait // for the data to load. @@ -27005,7 +27016,7 @@ function createFiberRoot( return root; } -var ReactVersion = "18.3.0-canary-191221fc"; +var ReactVersion = "18.3.0-canary-64e46017"; function createPortal$1( children, diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-prod.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-prod.fb.js index caab55daea..ae4c511a77 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-prod.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-prod.fb.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<3106445be52c70579494ac9a4777c8df>> + * @generated SignedSource<> */ "use strict"; @@ -7732,23 +7732,20 @@ function handleThrow(root, thrownValue) { ReactCurrentOwner.current = null; thrownValue === SuspenseException ? ((thrownValue = getSuspendedThenable()), - (workInProgressRootRenderLanes & 8388480) === - workInProgressRootRenderLanes - ? (root = null === shellBoundary ? !0 : !1) - : ((root = suspenseHandlerStackCursor.current), - (root = - null === root || - ((workInProgressRootRenderLanes & 125829120) !== - workInProgressRootRenderLanes && - 0 === (workInProgressRootRenderLanes & 1073741824)) - ? !1 - : root === shellBoundary)), + (root = suspenseHandlerStackCursor.current), (workInProgressSuspendedReason = - root && - 0 === (workInProgressRootSkippedLanes & 268435455) && - 0 === (workInProgressRootInterleavedUpdatedLanes & 268435455) - ? 2 - : 3)) + (null !== root && + ((workInProgressRootRenderLanes & 8388480) === + workInProgressRootRenderLanes + ? null !== shellBoundary + : ((workInProgressRootRenderLanes & 125829120) !== + workInProgressRootRenderLanes && + 0 === (workInProgressRootRenderLanes & 1073741824)) || + root !== shellBoundary)) || + 0 !== (workInProgressRootSkippedLanes & 268435455) || + 0 !== (workInProgressRootInterleavedUpdatedLanes & 268435455) + ? 3 + : 2)) : thrownValue === SuspenseyCommitException ? ((thrownValue = getSuspendedThenable()), (workInProgressSuspendedReason = 4)) @@ -8066,8 +8063,10 @@ function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { null === retryQueue ? (suspenseBoundary.updateQueue = new Set([wakeable])) : retryQueue.add(wakeable); + suspenseBoundary.mode & 1 && + attachPingListener(root, wakeable, thrownValue); } - break; + break a; case 22: if (suspenseBoundary.mode & 1) { suspenseBoundary.flags |= 65536; @@ -8088,20 +8087,18 @@ function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { ? (offscreenQueue.retryQueue = new Set([wakeable])) : retryQueue$32.add(wakeable); } + attachPingListener(root, wakeable, thrownValue); } - break; + break a; } - default: - throw Error( - "Unexpected Suspense handler tag (" + - suspenseBoundary.tag + - "). This is a bug in React." - ); } - suspenseBoundary.mode & 1 && - attachPingListener(root, wakeable, thrownValue); - break a; - } else if (1 === root.tag) { + throw Error( + "Unexpected Suspense handler tag (" + + suspenseBoundary.tag + + "). This is a bug in React." + ); + } + if (1 === root.tag) { attachPingListener(root, wakeable, thrownValue); renderDidSuspendDelayIfPossible(); break a; @@ -9421,7 +9418,7 @@ var roots = new Map(), devToolsConfig$jscomp$inline_1040 = { findFiberByHostInstance: getInstanceFromNode, bundleType: 0, - version: "18.3.0-canary-25ec80db", + version: "18.3.0-canary-9812ca1f", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForInstance: getInspectorDataForInstance, @@ -9464,7 +9461,7 @@ var internals$jscomp$inline_1282 = { scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-canary-25ec80db" + reconcilerVersion: "18.3.0-canary-9812ca1f" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_1283 = __REACT_DEVTOOLS_GLOBAL_HOOK__; diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js index 9d9d51a40b..628dd06e3f 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<> */ @@ -8263,23 +8263,20 @@ function handleThrow(root, thrownValue) { ReactCurrentOwner.current = null; thrownValue === SuspenseException ? ((thrownValue = getSuspendedThenable()), - (workInProgressRootRenderLanes & 8388480) === - workInProgressRootRenderLanes - ? (root = null === shellBoundary ? !0 : !1) - : ((root = suspenseHandlerStackCursor.current), - (root = - null === root || - ((workInProgressRootRenderLanes & 125829120) !== - workInProgressRootRenderLanes && - 0 === (workInProgressRootRenderLanes & 1073741824)) - ? !1 - : root === shellBoundary)), + (root = suspenseHandlerStackCursor.current), (workInProgressSuspendedReason = - root && - 0 === (workInProgressRootSkippedLanes & 268435455) && - 0 === (workInProgressRootInterleavedUpdatedLanes & 268435455) - ? 2 - : 3)) + (null !== root && + ((workInProgressRootRenderLanes & 8388480) === + workInProgressRootRenderLanes + ? null !== shellBoundary + : ((workInProgressRootRenderLanes & 125829120) !== + workInProgressRootRenderLanes && + 0 === (workInProgressRootRenderLanes & 1073741824)) || + root !== shellBoundary)) || + 0 !== (workInProgressRootSkippedLanes & 268435455) || + 0 !== (workInProgressRootInterleavedUpdatedLanes & 268435455) + ? 3 + : 2)) : thrownValue === SuspenseyCommitException ? ((thrownValue = getSuspendedThenable()), (workInProgressSuspendedReason = 4)) @@ -8664,8 +8661,10 @@ function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { null === retryQueue ? (suspenseBoundary.updateQueue = new Set([wakeable])) : retryQueue.add(wakeable); + suspenseBoundary.mode & 1 && + attachPingListener(root, wakeable, thrownValue); } - break; + break a; case 22: if (suspenseBoundary.mode & 1) { suspenseBoundary.flags |= 65536; @@ -8686,20 +8685,18 @@ function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { ? (offscreenQueue.retryQueue = new Set([wakeable])) : retryQueue$35.add(wakeable); } + attachPingListener(root, wakeable, thrownValue); } - break; + break a; } - default: - throw Error( - "Unexpected Suspense handler tag (" + - suspenseBoundary.tag + - "). This is a bug in React." - ); } - suspenseBoundary.mode & 1 && - attachPingListener(root, wakeable, thrownValue); - break a; - } else if (1 === root.tag) { + throw Error( + "Unexpected Suspense handler tag (" + + suspenseBoundary.tag + + "). This is a bug in React." + ); + } + if (1 === root.tag) { attachPingListener(root, wakeable, thrownValue); renderDidSuspendDelayIfPossible(); break a; @@ -10129,7 +10126,7 @@ var roots = new Map(), devToolsConfig$jscomp$inline_1118 = { findFiberByHostInstance: getInstanceFromNode, bundleType: 0, - version: "18.3.0-canary-d46b694e", + version: "18.3.0-canary-67d29d89", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForInstance: getInspectorDataForInstance, @@ -10185,7 +10182,7 @@ var roots = new Map(), scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-canary-d46b694e" + reconcilerVersion: "18.3.0-canary-67d29d89" }); exports.createPortal = function (children, containerTag) { return createPortal$1( diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js index 6a5727413b..7354b6e3db 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<096b1c8462af119e22314cca6718f66f>> + * @generated SignedSource<> */ 'use strict'; @@ -8107,7 +8107,14 @@ var SuspenseyCommitException = new Error( // for now this will do. var noopSuspenseyCommitThenable = { - then: function () {} + then: function () { + { + error( + "Internal React error: A listener was unexpectedly attached to a " + + '"noop" thenable. This is a bug in React. Please file an issue.' + ); + } + } }; function createThenableState() { // The ThenableState is created the first time a component suspends. If it @@ -15276,10 +15283,16 @@ function throwException( suspenseBoundary.updateQueue = new Set([wakeable]); } else { retryQueue.add(wakeable); + } // We only attach ping listeners in concurrent mode. Legacy + // Suspense always commits fallbacks synchronously, so there are + // no pings. + + if (suspenseBoundary.mode & ConcurrentMode) { + attachPingListener(root, wakeable, rootRenderLanes); } } - break; + return; } case OffscreenComponent: { @@ -15310,28 +15323,21 @@ function throwException( _retryQueue.add(wakeable); } } + + attachPingListener(root, wakeable, rootRenderLanes); } - break; - } // Fall through + return; + } } - - default: { - throw new Error( - "Unexpected Suspense handler tag (" + - suspenseBoundary.tag + - "). This " + - "is a bug in React." - ); - } - } // We only attach ping listeners in concurrent mode. Legacy Suspense always - // commits fallbacks synchronously, so there are no pings. - - if (suspenseBoundary.mode & ConcurrentMode) { - attachPingListener(root, wakeable, rootRenderLanes); } - return; + throw new Error( + "Unexpected Suspense handler tag (" + + suspenseBoundary.tag + + "). This " + + "is a bug in React." + ); } else { // No boundary was found. Unless this is a sync update, this is OK. // We can suspend and wait for more data to arrive. @@ -24362,9 +24368,19 @@ function shouldRemainOnPreviousScreen() { // on the previous screen, versus showing a fallback as soon as possible. It // takes into account both the priority of render and also whether showing a // fallback would produce a desirable user experience. - // TODO: Once `use` has fully replaced the `throw promise` pattern, we should + var handler = getSuspenseHandler(); + + if (handler === null) { + // There's no Suspense boundary that can provide a fallback. We have no + // choice but to remain on the previous screen. + // NOTE: We do this even for sync updates, for lack of any better option. In + // the future, we may change how we handle this, like by putting the whole + // root into a "detached" mode. + return true; + } // TODO: Once `use` has fully replaced the `throw promise` pattern, we should // be able to remove the equivalent check in finishConcurrentRender, and rely // just on this one. + if (includesOnlyTransitions(workInProgressRootRenderLanes)) { if (getShellBoundary() === null) { // We're rendering inside the "shell" of the app. Activating the nearest @@ -24380,26 +24396,21 @@ function shouldRemainOnPreviousScreen() { } } - var handler = getSuspenseHandler(); - - if (handler === null); - else { - if ( - includesOnlyRetries(workInProgressRootRenderLanes) || // In this context, an OffscreenLane counts as a Retry - // TODO: It's become increasingly clear that Retries and Offscreen are - // deeply connected. They probably can be unified further. - includesSomeLane(workInProgressRootRenderLanes, OffscreenLane) - ) { - // During a retry, we can suspend rendering if the nearest Suspense boundary - // is the boundary of the "shell", because we're guaranteed not to block - // any new content from appearing. - // - // The reason we must check if this is a retry is because it guarantees - // that suspending the work loop won't block an actual update, because - // retries don't "update" anything; they fill in fallbacks that were left - // behind by a previous transition. - return handler === getShellBoundary(); - } + if ( + includesOnlyRetries(workInProgressRootRenderLanes) || // In this context, an OffscreenLane counts as a Retry + // TODO: It's become increasingly clear that Retries and Offscreen are + // deeply connected. They probably can be unified further. + includesSomeLane(workInProgressRootRenderLanes, OffscreenLane) + ) { + // During a retry, we can suspend rendering if the nearest Suspense boundary + // is the boundary of the "shell", because we're guaranteed not to block + // any new content from appearing. + // + // The reason we must check if this is a retry is because it guarantees + // that suspending the work loop won't block an actual update, because + // retries don't "update" anything; they fill in fallbacks that were left + // behind by a previous transition. + return handler === getShellBoundary(); } // For all other Lanes besides Transitions and Retries, we should not wait // for the data to load. @@ -27519,7 +27530,7 @@ function createFiberRoot( return root; } -var ReactVersion = "18.3.0-canary-439c5f24"; +var ReactVersion = "18.3.0-canary-2a0c5fa6"; function createPortal$1( children, diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js index 2427fbaecd..b446132113 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<51235cc0d10c7c67758da65bf9e82cd7>> + * @generated SignedSource<<3912084f06749c92cbe914e3b90809c6>> */ "use strict"; @@ -7981,23 +7981,20 @@ function handleThrow(root, thrownValue) { ReactCurrentOwner.current = null; thrownValue === SuspenseException ? ((thrownValue = getSuspendedThenable()), - (workInProgressRootRenderLanes & 8388480) === - workInProgressRootRenderLanes - ? (root = null === shellBoundary ? !0 : !1) - : ((root = suspenseHandlerStackCursor.current), - (root = - null === root || - ((workInProgressRootRenderLanes & 125829120) !== - workInProgressRootRenderLanes && - 0 === (workInProgressRootRenderLanes & 1073741824)) - ? !1 - : root === shellBoundary)), + (root = suspenseHandlerStackCursor.current), (workInProgressSuspendedReason = - root && - 0 === (workInProgressRootSkippedLanes & 268435455) && - 0 === (workInProgressRootInterleavedUpdatedLanes & 268435455) - ? 2 - : 3)) + (null !== root && + ((workInProgressRootRenderLanes & 8388480) === + workInProgressRootRenderLanes + ? null !== shellBoundary + : ((workInProgressRootRenderLanes & 125829120) !== + workInProgressRootRenderLanes && + 0 === (workInProgressRootRenderLanes & 1073741824)) || + root !== shellBoundary)) || + 0 !== (workInProgressRootSkippedLanes & 268435455) || + 0 !== (workInProgressRootInterleavedUpdatedLanes & 268435455) + ? 3 + : 2)) : thrownValue === SuspenseyCommitException ? ((thrownValue = getSuspendedThenable()), (workInProgressSuspendedReason = 4)) @@ -8315,8 +8312,10 @@ function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { null === retryQueue ? (suspenseBoundary.updateQueue = new Set([wakeable])) : retryQueue.add(wakeable); + suspenseBoundary.mode & 1 && + attachPingListener(root, wakeable, thrownValue); } - break; + break a; case 22: if (suspenseBoundary.mode & 1) { suspenseBoundary.flags |= 65536; @@ -8337,20 +8336,18 @@ function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { ? (offscreenQueue.retryQueue = new Set([wakeable])) : retryQueue$34.add(wakeable); } + attachPingListener(root, wakeable, thrownValue); } - break; + break a; } - default: - throw Error( - "Unexpected Suspense handler tag (" + - suspenseBoundary.tag + - "). This is a bug in React." - ); } - suspenseBoundary.mode & 1 && - attachPingListener(root, wakeable, thrownValue); - break a; - } else if (1 === root.tag) { + throw Error( + "Unexpected Suspense handler tag (" + + suspenseBoundary.tag + + "). This is a bug in React." + ); + } + if (1 === root.tag) { attachPingListener(root, wakeable, thrownValue); renderDidSuspendDelayIfPossible(); break a; @@ -9677,7 +9674,7 @@ var roots = new Map(), devToolsConfig$jscomp$inline_1095 = { findFiberByHostInstance: getInstanceFromTag, bundleType: 0, - version: "18.3.0-canary-37d552e6", + version: "18.3.0-canary-5a0cdf8c", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForInstance: getInspectorDataForInstance, @@ -9720,7 +9717,7 @@ var internals$jscomp$inline_1351 = { scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-canary-37d552e6" + reconcilerVersion: "18.3.0-canary-5a0cdf8c" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_1352 = __REACT_DEVTOOLS_GLOBAL_HOOK__; diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js index 12681916a9..01c8abee46 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<<652f44316e146b8f03b47dda41701ba7>> */ @@ -8512,23 +8512,20 @@ function handleThrow(root, thrownValue) { ReactCurrentOwner.current = null; thrownValue === SuspenseException ? ((thrownValue = getSuspendedThenable()), - (workInProgressRootRenderLanes & 8388480) === - workInProgressRootRenderLanes - ? (root = null === shellBoundary ? !0 : !1) - : ((root = suspenseHandlerStackCursor.current), - (root = - null === root || - ((workInProgressRootRenderLanes & 125829120) !== - workInProgressRootRenderLanes && - 0 === (workInProgressRootRenderLanes & 1073741824)) - ? !1 - : root === shellBoundary)), + (root = suspenseHandlerStackCursor.current), (workInProgressSuspendedReason = - root && - 0 === (workInProgressRootSkippedLanes & 268435455) && - 0 === (workInProgressRootInterleavedUpdatedLanes & 268435455) - ? 2 - : 3)) + (null !== root && + ((workInProgressRootRenderLanes & 8388480) === + workInProgressRootRenderLanes + ? null !== shellBoundary + : ((workInProgressRootRenderLanes & 125829120) !== + workInProgressRootRenderLanes && + 0 === (workInProgressRootRenderLanes & 1073741824)) || + root !== shellBoundary)) || + 0 !== (workInProgressRootSkippedLanes & 268435455) || + 0 !== (workInProgressRootInterleavedUpdatedLanes & 268435455) + ? 3 + : 2)) : thrownValue === SuspenseyCommitException ? ((thrownValue = getSuspendedThenable()), (workInProgressSuspendedReason = 4)) @@ -8913,8 +8910,10 @@ function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { null === retryQueue ? (suspenseBoundary.updateQueue = new Set([wakeable])) : retryQueue.add(wakeable); + suspenseBoundary.mode & 1 && + attachPingListener(root, wakeable, thrownValue); } - break; + break a; case 22: if (suspenseBoundary.mode & 1) { suspenseBoundary.flags |= 65536; @@ -8935,20 +8934,18 @@ function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { ? (offscreenQueue.retryQueue = new Set([wakeable])) : retryQueue$37.add(wakeable); } + attachPingListener(root, wakeable, thrownValue); } - break; + break a; } - default: - throw Error( - "Unexpected Suspense handler tag (" + - suspenseBoundary.tag + - "). This is a bug in React." - ); } - suspenseBoundary.mode & 1 && - attachPingListener(root, wakeable, thrownValue); - break a; - } else if (1 === root.tag) { + throw Error( + "Unexpected Suspense handler tag (" + + suspenseBoundary.tag + + "). This is a bug in React." + ); + } + if (1 === root.tag) { attachPingListener(root, wakeable, thrownValue); renderDidSuspendDelayIfPossible(); break a; @@ -10385,7 +10382,7 @@ var roots = new Map(), devToolsConfig$jscomp$inline_1173 = { findFiberByHostInstance: getInstanceFromTag, bundleType: 0, - version: "18.3.0-canary-1af01c24", + version: "18.3.0-canary-c231d0c6", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForInstance: getInspectorDataForInstance, @@ -10441,7 +10438,7 @@ var roots = new Map(), scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-canary-1af01c24" + reconcilerVersion: "18.3.0-canary-c231d0c6" }); exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = { computeComponentStackForErrorReporting: function (reactTag) {