Skip to content

Commit cfd9d8c

Browse files
committed
Revert "Allow transitions to interrupt Suspensey commits (#26531)"
This reverts commit 8888746.
1 parent 314f7d3 commit cfd9d8c

File tree

4 files changed

+65
-40
lines changed

4 files changed

+65
-40
lines changed

packages/react-dom/src/__tests__/ReactDOMFloat-test.js

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3216,7 +3216,7 @@ body {
32163216
);
32173217
});
32183218

3219-
it('can interrupt a suspended commit with a new transition', async () => {
3219+
it('can start a new suspended commit after a previous one finishes', async () => {
32203220
function App({children}) {
32213221
return (
32223222
<html>
@@ -3225,66 +3225,81 @@ body {
32253225
);
32263226
}
32273227
const root = ReactDOMClient.createRoot(document);
3228-
root.render(<App>(empty)</App>);
3229-
3230-
// Start a transition to "A"
3228+
root.render(<App />);
32313229
React.startTransition(() => {
32323230
root.render(
32333231
<App>
3234-
A
3235-
<link rel="stylesheet" href="A" precedence="default" />
3232+
hello
3233+
<link rel="stylesheet" href="foo" precedence="default" />
32363234
</App>,
32373235
);
32383236
});
32393237
await waitForAll([]);
3240-
3241-
// "A" hasn't loaded yet, so we remain on the initial UI. Its preload
3242-
// has been inserted into the head, though.
32433238
expect(getMeaningfulChildren(document)).toEqual(
32443239
<html>
32453240
<head>
3246-
<link rel="preload" href="A" as="style" />
3241+
<link rel="preload" href="foo" as="style" />
32473242
</head>
3248-
<body>(empty)</body>
3243+
<body />
32493244
</html>,
32503245
);
32513246

3252-
// Interrupt the "A" transition with a new one, "B"
32533247
React.startTransition(() => {
32543248
root.render(
32553249
<App>
3256-
B
3257-
<link rel="stylesheet" href="B" precedence="default" />
3250+
hello2
3251+
{null}
3252+
<link rel="stylesheet" href="bar" precedence="default" />
32583253
</App>,
32593254
);
32603255
});
32613256
await waitForAll([]);
3257+
expect(getMeaningfulChildren(document)).toEqual(
3258+
<html>
3259+
<head>
3260+
<link rel="preload" href="foo" as="style" />
3261+
</head>
3262+
<body />
3263+
</html>,
3264+
);
32623265

3263-
// Still on the initial UI because "B" hasn't loaded, but its preload
3264-
// is now in the head, too.
3266+
loadPreloads();
3267+
loadStylesheets();
3268+
assertLog(['load preload: foo', 'load stylesheet: foo']);
32653269
expect(getMeaningfulChildren(document)).toEqual(
32663270
<html>
32673271
<head>
3268-
<link rel="preload" href="A" as="style" />
3269-
<link rel="preload" href="B" as="style" />
3272+
<link rel="stylesheet" href="foo" data-precedence="default" />
3273+
<link rel="preload" href="foo" as="style" />
32703274
</head>
3271-
<body>(empty)</body>
3275+
<body>hello</body>
32723276
</html>,
32733277
);
32743278

3275-
// Finish loading
3279+
// The second update should process now
3280+
await waitForAll([]);
3281+
expect(getMeaningfulChildren(document)).toEqual(
3282+
<html>
3283+
<head>
3284+
<link rel="stylesheet" href="foo" data-precedence="default" />
3285+
<link rel="preload" href="foo" as="style" />
3286+
<link rel="preload" href="bar" as="style" />
3287+
</head>
3288+
<body>hello</body>
3289+
</html>,
3290+
);
32763291
loadPreloads();
32773292
loadStylesheets();
3278-
assertLog(['load preload: A', 'load preload: B', 'load stylesheet: B']);
3279-
// The "B" transition has finished.
3293+
assertLog(['load preload: bar', 'load stylesheet: bar']);
32803294
expect(getMeaningfulChildren(document)).toEqual(
32813295
<html>
32823296
<head>
3283-
<link rel="stylesheet" href="B" data-precedence="default" />
3284-
<link rel="preload" href="A" as="style" />
3285-
<link rel="preload" href="B" as="style" />
3297+
<link rel="stylesheet" href="foo" data-precedence="default" />
3298+
<link rel="stylesheet" href="bar" data-precedence="default" />
3299+
<link rel="preload" href="foo" as="style" />
3300+
<link rel="preload" href="bar" as="style" />
32863301
</head>
3287-
<body>B</body>
3302+
<body>hello2</body>
32883303
</html>,
32893304
);
32903305
});

packages/react-reconciler/src/ReactFiberRootScheduler.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
SyncLane,
1919
getHighestPriorityLane,
2020
getNextLanes,
21+
includesOnlyNonUrgentLanes,
2122
includesSyncLane,
2223
markStarvedLanesAsExpired,
2324
} from './ReactFiberLane';
@@ -291,16 +292,14 @@ function scheduleTaskForRootDuringMicrotask(
291292

292293
const existingCallbackNode = root.callbackNode;
293294
if (
294-
// Check if there's nothing to work on
295295
nextLanes === NoLanes ||
296296
// If this root is currently suspended and waiting for data to resolve, don't
297297
// schedule a task to render it. We'll either wait for a ping, or wait to
298298
// receive an update.
299-
//
300-
// Suspended render phase
301-
(root === workInProgressRoot && isWorkLoopSuspendedOnData()) ||
302-
// Suspended commit phase
303-
root.cancelPendingCommit !== null
299+
(isWorkLoopSuspendedOnData() && root === workInProgressRoot) ||
300+
// We should only interrupt a pending commit if the new update
301+
// is urgent.
302+
(root.cancelPendingCommit !== null && includesOnlyNonUrgentLanes(nextLanes))
304303
) {
305304
// Fast path: There's nothing to work on.
306305
if (existingCallbackNode !== null) {

packages/react-reconciler/src/ReactFiberWorkLoop.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -725,11 +725,8 @@ export function scheduleUpdateOnFiber(
725725
// Check if the work loop is currently suspended and waiting for data to
726726
// finish loading.
727727
if (
728-
// Suspended render phase
729-
(root === workInProgressRoot &&
730-
workInProgressSuspendedReason === SuspendedOnData) ||
731-
// Suspended commit phase
732-
root.cancelPendingCommit !== null
728+
workInProgressSuspendedReason === SuspendedOnData &&
729+
root === workInProgressRoot
733730
) {
734731
// The incoming update might unblock the current render. Interrupt the
735732
// current attempt and restart from the top.

packages/react-reconciler/src/__tests__/ReactSuspenseyCommitPhase-test.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,15 +137,15 @@ describe('ReactSuspenseyCommitPhase', () => {
137137
// Nothing showing yet.
138138
expect(root).toMatchRenderedOutput(null);
139139

140-
// If there's an update, it should interrupt the suspended commit.
140+
// If there's an urgent update, it should interrupt the suspended commit.
141141
await act(() => {
142142
root.render(<Text text="Something else" />);
143143
});
144144
assertLog(['Something else']);
145145
expect(root).toMatchRenderedOutput('Something else');
146146
});
147147

148-
test('a transition update interrupts a suspended commit', async () => {
148+
test('a non-urgent update does not interrupt a suspended commit', async () => {
149149
const root = ReactNoop.createRoot();
150150

151151
// Mount an image. This transition will suspend because it's not inside a
@@ -159,12 +159,26 @@ describe('ReactSuspenseyCommitPhase', () => {
159159
// Nothing showing yet.
160160
expect(root).toMatchRenderedOutput(null);
161161

162-
// If there's an update, it should interrupt the suspended commit.
162+
// If there's another transition update, it should not interrupt the
163+
// suspended commit.
163164
await act(() => {
164165
startTransition(() => {
165166
root.render(<Text text="Something else" />);
166167
});
167168
});
169+
// Still suspended.
170+
expect(root).toMatchRenderedOutput(null);
171+
172+
await act(() => {
173+
// Resolving the image should result in an immediate, synchronous commit.
174+
resolveSuspenseyThing('A');
175+
expect(root).toMatchRenderedOutput(<suspensey-thing src="A" />);
176+
});
177+
// Then the second transition is unblocked.
178+
// TODO: Right now the only way to unsuspend a commit early is to proceed
179+
// with the commit even if everything isn't ready. Maybe there should also
180+
// be a way to abort a commit so that it can be interrupted by
181+
// another transition.
168182
assertLog(['Something else']);
169183
expect(root).toMatchRenderedOutput('Something else');
170184
});

0 commit comments

Comments
 (0)