[react-dom] Enforce small gap between completed navigation and default Transition indicator (#33354)
Sebastian "Sebbie" Silbermann committed
May 28, 2025 at 19:46 UTC
5717f1933f2e8b10406fde1043c3047cbfbddc82
3 files changed
+45
-2
fixtures/flight/src/App.js
+2
@@ -12,6 +12,7 @@ import Button from './Button.js';
12
import Form from './Form.js';
13
import {Dynamic} from './Dynamic.js';
14
import {Client} from './Client.js';
15
+import {Navigate} from './Navigate.js';
16
17
import {Note} from './cjs/Note.js';
18
@@ -89,6 +90,7 @@ export default async function App({prerender}) {
90
<Note />
91
<Foo>{dedupedChild}</Foo>
92
<Bar>{Promise.resolve([dedupedChild])}</Bar>
93
+ <Navigate />
94
</Container>
95
</body>
96
</html>
fixtures/flight/src/Navigate.js
new
+40
@@ -0,0 +1,40 @@
1
+'use client';
2
+
3
+import * as React from 'react';
4
+import Container from './Container.js';
5
+
6
+export function Navigate() {
7
+ /** Repro for https://issues.chromium.org/u/1/issues/419746417 */
8
+ function provokeChromeCrash() {
9
+ React.startTransition(async () => {
10
+ console.log('Default transition triggered');
11
+
12
+ await new Promise(resolve => {
13
+ setTimeout(
14
+ () => {
15
+ history.pushState(
16
+ {},
17
+ '',
18
+ `?chrome-crash-419746417=${performance.now()}`
19
+ );
20
+ },
21
+ // This needs to happen before React's default transition indicator
22
+ // is displayed but after it's scheduled.
23
+ 100 + -50
24
+ );
25
+
26
+ setTimeout(() => {
27
+ console.log('Default transition completed');
28
+ resolve();
29
+ }, 1000);
30
+ });
31
+ });
32
+ }
33
+
34
+ return (
35
+ <Container>
36
+ <h2>Navigation fixture</h2>
37
+ <button onClick={provokeChromeCrash}>Provoke Chrome Crash (fixed)</button>
38
+ </Container>
39
+ );
40
+}
packages/react-dom/src/client/ReactDOMDefaultTransitionIndicator.js
+3
-2
@@ -38,7 +38,8 @@ export function defaultOnDefaultTransitionIndicator(): void | (() => void) {
38
if (!isCancelled) {
39
// Some other navigation completed but we should still be running.
40
// Start another fake one to keep the loading indicator going.
41
- startFakeNavigation();
41
+ // There needs to be an async gap to work around https://issues.chromium.org/u/1/issues/419746417.
42
+ setTimeout(startFakeNavigation, 20);
43
}
44
}
45
@@ -70,7 +71,7 @@ export function defaultOnDefaultTransitionIndicator(): void | (() => void) {
71
}
72
}
73
73
- // Delay the start a bit in case this is a fast navigation.
74
+ // Delay the start a bit in case this is a fast Transition.
75
setTimeout(startFakeNavigation, 100);
76
77
return function () {