diff --git a/fixtures/flight/src/App.js b/fixtures/flight/src/App.js index 2f2118580a93c..7b811dd7628e0 100644 --- a/fixtures/flight/src/App.js +++ b/fixtures/flight/src/App.js @@ -12,6 +12,7 @@ import Button from './Button.js'; import Form from './Form.js'; import {Dynamic} from './Dynamic.js'; import {Client} from './Client.js'; +import {Navigate} from './Navigate.js'; import {Note} from './cjs/Note.js'; @@ -89,6 +90,7 @@ export default async function App({prerender}) { {dedupedChild} {Promise.resolve([dedupedChild])} + diff --git a/fixtures/flight/src/Navigate.js b/fixtures/flight/src/Navigate.js new file mode 100644 index 0000000000000..4436b9fdf7d2e --- /dev/null +++ b/fixtures/flight/src/Navigate.js @@ -0,0 +1,40 @@ +'use client'; + +import * as React from 'react'; +import Container from './Container.js'; + +export function Navigate() { + /** Repro for https://issues.chromium.org/u/1/issues/419746417 */ + function provokeChromeCrash() { + React.startTransition(async () => { + console.log('Default transition triggered'); + + await new Promise(resolve => { + setTimeout( + () => { + history.pushState( + {}, + '', + `?chrome-crash-419746417=${performance.now()}` + ); + }, + // This needs to happen before React's default transition indicator + // is displayed but after it's scheduled. + 100 + -50 + ); + + setTimeout(() => { + console.log('Default transition completed'); + resolve(); + }, 1000); + }); + }); + } + + return ( + +

Navigation fixture

+ +
+ ); +} diff --git a/packages/react-dom/src/client/ReactDOMDefaultTransitionIndicator.js b/packages/react-dom/src/client/ReactDOMDefaultTransitionIndicator.js index 8f1a32d826c1a..37661849cad87 100644 --- a/packages/react-dom/src/client/ReactDOMDefaultTransitionIndicator.js +++ b/packages/react-dom/src/client/ReactDOMDefaultTransitionIndicator.js @@ -38,7 +38,8 @@ export function defaultOnDefaultTransitionIndicator(): void | (() => void) { if (!isCancelled) { // Some other navigation completed but we should still be running. // Start another fake one to keep the loading indicator going. - startFakeNavigation(); + // There needs to be an async gap to work around https://issues.chromium.org/u/1/issues/419746417. + setTimeout(startFakeNavigation, 20); } } @@ -70,7 +71,7 @@ export function defaultOnDefaultTransitionIndicator(): void | (() => void) { } } - // Delay the start a bit in case this is a fast navigation. + // Delay the start a bit in case this is a fast Transition. setTimeout(startFakeNavigation, 100); return function () {