From d8c7064f089c3bff70b439cb7ec55ac1e4aea138 Mon Sep 17 00:00:00 2001 From: Jason Pickens Date: Mon, 26 Feb 2024 15:17:45 +1300 Subject: [PATCH] Fix router re-initialization bug (#11300). --- packages/react-router/lib/components.tsx | 55 ++++++++++++++---------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/packages/react-router/lib/components.tsx b/packages/react-router/lib/components.tsx index 918bc34d39..b1d171565b 100644 --- a/packages/react-router/lib/components.tsx +++ b/packages/react-router/lib/components.tsx @@ -14,14 +14,15 @@ import { AbortedDeferredError, Action as NavigationType, createMemoryHistory, - UNSAFE_getResolveToMatches as getResolveToMatches, - UNSAFE_invariant as invariant, parsePath, resolveTo, stripBasename, + UNSAFE_getResolveToMatches as getResolveToMatches, + UNSAFE_invariant as invariant, UNSAFE_warning as warning, } from "@remix-run/router"; import * as React from "react"; +import { useEffect, useRef } from "react"; import type { DataRouteObject, @@ -64,26 +65,26 @@ export interface RouterProviderProps { } /** - Webpack + React 17 fails to compile on any of the following because webpack - complains that `startTransition` doesn't exist in `React`: - * import { startTransition } from "react" - * import * as React from from "react"; - "startTransition" in React ? React.startTransition(() => setState()) : setState() - * import * as React from from "react"; - "startTransition" in React ? React["startTransition"](() => setState()) : setState() - - Moving it to a constant such as the following solves the Webpack/React 17 issue: - * import * as React from from "react"; - const START_TRANSITION = "startTransition"; - START_TRANSITION in React ? React[START_TRANSITION](() => setState()) : setState() - - However, that introduces webpack/terser minification issues in production builds - in React 18 where minification/obfuscation ends up removing the call of - React.startTransition entirely from the first half of the ternary. Grabbing - this exported reference once up front resolves that issue. - - See https://github.com/remix-run/react-router/issues/10579 -*/ + Webpack + React 17 fails to compile on any of the following because webpack + complains that `startTransition` doesn't exist in `React`: + * import { startTransition } from "react" + * import * as React from from "react"; + "startTransition" in React ? React.startTransition(() => setState()) : setState() + * import * as React from from "react"; + "startTransition" in React ? React["startTransition"](() => setState()) : setState() + + Moving it to a constant such as the following solves the Webpack/React 17 issue: + * import * as React from from "react"; + const START_TRANSITION = "startTransition"; + START_TRANSITION in React ? React[START_TRANSITION](() => setState()) : setState() + + However, that introduces webpack/terser minification issues in production builds + in React 18 where minification/obfuscation ends up removing the call of + React.startTransition entirely from the first half of the ternary. Grabbing + this exported reference once up front resolves that issue. + + See https://github.com/remix-run/react-router/issues/10579 + */ const START_TRANSITION = "startTransition"; const startTransitionImpl = React[START_TRANSITION]; @@ -154,6 +155,14 @@ export function RouterProvider({ [router, navigator, basename] ); + const wasRouterPreviouslyInitialized = useRef(false); + const isRouterInitialized = router.state.initialized; + const routerReinitializing = + wasRouterPreviouslyInitialized && !isRouterInitialized; + useEffect(() => { + wasRouterPreviouslyInitialized.current = isRouterInitialized; + }, [wasRouterPreviouslyInitialized, isRouterInitialized]); + // The fragment and {null} here are important! We need them to keep React 18's // useId happy when we are server-rendering since we may have a