Skip to content

Commit 21ead2c

Browse files
committed
Ensure we rerender with the original suspender
1 parent 848d916 commit 21ead2c

File tree

7 files changed

+64
-44
lines changed

7 files changed

+64
-44
lines changed

fixtures/fizz/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"start": "concurrently \"npm run start:server\" \"npm run start:bundler\"",
3535
"dev:server": "cross-env NODE_ENV=development nodemon -- --inspect server/server.js",
3636
"start:server": "cross-env NODE_ENV=production nodemon -- server/server.js",
37-
"dev:bundler": "cross-env NODE_ENV=development nodemon -- scripts/build.js",
37+
"dev:bundler": "cross-env NODE_OPTIONS=--openssl-legacy-provider NODE_ENV=development nodemon -- scripts/build.js",
3838
"start:bundler": "cross-env NODE_ENV=production nodemon -- scripts/build.js"
3939
},
4040
"babel": {

fixtures/fizz/server/delays.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
exports.API_DELAY = 2000;
1313

1414
// How long the server waits for data before giving up.
15-
exports.ABORT_DELAY = 10000;
15+
exports.ABORT_DELAY = 1;
1616

1717
// How long serving the JS bundles is delayed.
1818
exports.JS_BUNDLE_DELAY = 4000;

fixtures/fizz/src/App.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ export default function App({assets, promise, title}) {
2626
return (
2727
<Html assets={assets} title={title}>
2828
<h1>{title}</h1>
29-
{components}
3029
<h1>all done</h1>
3130
<h2>or maybe not</h2>
3231
<Suspense fallback="loading more...">

fixtures/fizz/yarn.lock

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3176,7 +3176,7 @@ isobject@^3.0.0, isobject@^3.0.1:
31763176
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
31773177
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
31783178

3179-
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
3179+
js-tokens@^4.0.0:
31803180
version "4.0.0"
31813181
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
31823182
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
@@ -3300,13 +3300,6 @@ lodash@^4.17.15, lodash@^4.17.19:
33003300
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
33013301
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
33023302

3303-
loose-envify@^1.1.0:
3304-
version "1.4.0"
3305-
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
3306-
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
3307-
dependencies:
3308-
js-tokens "^3.0.0 || ^4.0.0"
3309-
33103303
lowercase-keys@^1.0.0, lowercase-keys@^1.0.1:
33113304
version "1.0.1"
33123305
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
@@ -4095,13 +4088,12 @@ rc@^1.2.8:
40954088
minimist "^1.2.0"
40964089
strip-json-comments "~2.0.1"
40974090

4098-
react-dom@^18.2.0:
4099-
version "18.2.0"
4100-
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
4101-
integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
4091+
react-dom@^19.0.0:
4092+
version "19.2.0"
4093+
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.2.0.tgz#00ed1e959c365e9a9d48f8918377465466ec3af8"
4094+
integrity sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==
41024095
dependencies:
4103-
loose-envify "^1.1.0"
4104-
scheduler "^0.23.0"
4096+
scheduler "^0.27.0"
41054097

41064098
react-error-boundary@^3.1.3:
41074099
version "3.1.4"
@@ -4110,12 +4102,10 @@ react-error-boundary@^3.1.3:
41104102
dependencies:
41114103
"@babel/runtime" "^7.12.5"
41124104

4113-
react@^18.2.0:
4114-
version "18.2.0"
4115-
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
4116-
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
4117-
dependencies:
4118-
loose-envify "^1.1.0"
4105+
react@^19.0.0:
4106+
version "19.2.0"
4107+
resolved "https://registry.yarnpkg.com/react/-/react-19.2.0.tgz#d33dd1721698f4376ae57a54098cb47fc75d93a5"
4108+
integrity sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==
41194109

41204110
read-pkg@^4.0.1:
41214111
version "4.0.1"
@@ -4383,12 +4373,10 @@ safe-regex@^1.1.0:
43834373
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
43844374
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
43854375

4386-
scheduler@^0.23.0:
4387-
version "0.23.0"
4388-
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
4389-
integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
4390-
dependencies:
4391-
loose-envify "^1.1.0"
4376+
scheduler@^0.27.0:
4377+
version "0.27.0"
4378+
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.27.0.tgz#0c4ef82d67d1e5c1e359e8fc76d3a87f045fe5bd"
4379+
integrity sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==
43924380

43934381
schema-utils@^1.0.0:
43944382
version "1.0.0"

packages/react-server/src/ReactFizzServer.js

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ import isArray from 'shared/isArray';
193193
import {
194194
SuspenseException,
195195
getSuspendedThenable,
196+
ensureSuspendableThenableStateDEV,
196197
getSuspendedCallSiteStackDEV,
197198
getSuspendedCallSiteDebugTaskDEV,
198199
setCaptureSuspendedCallSiteDEV,
@@ -1030,7 +1031,7 @@ function pushHaltedAwaitOnComponentStack(
10301031
}
10311032

10321033
// performWork + retryTask without mutation
1033-
function rerenderHaltedTask(request: Request, task: Task): void {
1034+
function rerenderStalledTask(request: Request, task: Task): void {
10341035
const prevContext = getActiveContext();
10351036
const prevDispatcher = ReactSharedInternals.H;
10361037
ReactSharedInternals.H = HooksDispatcher;
@@ -1080,9 +1081,14 @@ function pushSuspendedCallSiteOnComponentStack(
10801081
task: Task,
10811082
): void {
10821083
setCaptureSuspendedCallSiteDEV(true);
1084+
const restoreThenableState = ensureSuspendableThenableStateDEV(
1085+
// refined at the callsite
1086+
((task.thenableState: any): ThenableState),
1087+
);
10831088
try {
1084-
rerenderHaltedTask(request, task);
1089+
rerenderStalledTask(request, task);
10851090
} finally {
1091+
restoreThenableState();
10861092
setCaptureSuspendedCallSiteDEV(false);
10871093
}
10881094

@@ -4616,13 +4622,6 @@ function abortTask(task: Task, request: Request, error: mixed): void {
46164622
}
46174623
pushHaltedAwaitOnComponentStack(task, debugInfo);
46184624
if (task.thenableState !== null) {
4619-
// TODO: really?
4620-
// If the thenable was resolved in the meantime, we won't get a stack.
4621-
// We won't know which thenable in thenableState is newly settled though.
4622-
// We can't just clear status fields on each thenable because then the
4623-
// stack may point at a thenable that wasn't stalled. In those cases
4624-
// it's better to point at the callsite of the stalled Component as an
4625-
// entrypoint instead of the wrong thenable.
46264625
pushSuspendedCallSiteOnComponentStack(request, task);
46274626
}
46284627
}

packages/react-server/src/ReactFizzThenable.js

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,9 @@
77
* @flow
88
*/
99

10-
// Corresponds to ReactFiberWakeable and ReactFlightWakeable modules. Generally,
10+
// Corresponds to ReactFiberThenable and ReactFlightThenable modules. Generally,
1111
// changes to one module should be reflected in the others.
1212

13-
// TODO: Rename this module and the corresponding Fiber one to "Thenable"
14-
// instead of "Wakeable". Or some other more appropriate name.
15-
1613
import type {
1714
Thenable,
1815
PendingThenable,
@@ -185,6 +182,10 @@ export function setCaptureSuspendedCallSiteDEV(capture: boolean): void {
185182
let suspendedCallSiteStack: ComponentStackNode | null = null;
186183
let suspendedCallSiteDebugTask: ConsoleTask | null = null;
187184
function captureSuspendedCallSite(): void {
185+
// This is currently only used when aborting in Fizz.
186+
// You can only abort the render in Fizz and Flight.
187+
// In Fiber we only track suspended use via DevTools.
188+
// In Flight, we track suspended use via async debug info.
188189
const currentTask = currentTaskInDEV;
189190
if (currentTask === null) {
190191
// eslint-disable-next-line react-internal/prod-error-codes -- not a prod error
@@ -248,3 +249,36 @@ export function getSuspendedCallSiteDebugTaskDEV(): ConsoleTask | null {
248249
);
249250
}
250251
}
252+
253+
export function ensureSuspendableThenableStateDEV(
254+
thenableState: ThenableState,
255+
): () => void {
256+
if (__DEV__) {
257+
const lastThenable = thenableState[thenableState.length - 1];
258+
switch (lastThenable.status) {
259+
case 'fulfilled':
260+
const previousThenableValue = lastThenable.value;
261+
delete lastThenable.value;
262+
delete (lastThenable: any).status;
263+
return () => {
264+
lastThenable.value = previousThenableValue;
265+
lastThenable.status = 'fulfilled';
266+
};
267+
case 'rejected':
268+
const previousThenableReason = lastThenable.reason;
269+
delete lastThenable.reason;
270+
delete (lastThenable: any).status;
271+
return () => {
272+
lastThenable.reason = previousThenableReason;
273+
lastThenable.status = 'rejected';
274+
};
275+
}
276+
return noop;
277+
} else {
278+
// eslint-disable-next-line react-internal/prod-error-codes
279+
throw new Error(
280+
'ensureSuspendableThenableStateDEV was called in a production environment. ' +
281+
'This is a bug in React.',
282+
);
283+
}
284+
}

packages/react-server/src/__tests__/ReactServer-test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,8 @@ describe('ReactServer', () => {
163163
__DEV__
164164
? '' +
165165
// The concrete location may change as this test is updated
166-
// Just make sure they still point at the same code
167-
'\n at Component (./ReactServer-test.js:95:13)' +
166+
// Just make sure they still point at React.use(p2)
167+
'\n at Component (./ReactServer-test.js:94:13)' +
168168
'\n at Indirection (./ReactServer-test.js:101:44)' +
169169
'\n at App (./ReactServer-test.js:109:46)'
170170
: null,

0 commit comments

Comments
 (0)