import type { InitialEntry, LazyRouteFunction, Location, MemoryHistory, RelativeRoutingType, Router as RemixRouter, RouterState, RouterSubscriber, To, TrackedPromise, } from "@remix-run/router"; import { AbortedDeferredError, Action as NavigationType, createMemoryHistory, UNSAFE_getResolveToMatches as getResolveToMatches, UNSAFE_invariant as invariant, parsePath, resolveTo, stripBasename, UNSAFE_warning as warning, } from "@remix-run/router"; import * as React from "react"; import type { DataRouteObject, IndexRouteObject, Navigator, NonIndexRouteObject, RouteMatch, RouteObject, } from "./context"; import { AwaitContext, DataRouterContext, DataRouterStateContext, LocationContext, NavigationContext, RouteContext, } from "./context"; import { _renderMatches, useAsyncValue, useInRouterContext, useLocation, useNavigate, useOutlet, useRoutes, useRoutesImpl, } from "./hooks"; import { logV6DeprecationWarnings } from "./deprecations"; export interface FutureConfig { v7_relativeSplatPath: boolean; v7_startTransition: boolean; } export interface RouterProviderProps { fallbackElement?: React.ReactNode; router: RemixRouter; // Only accept future flags relevant to rendering behavior // routing flags should be accessed via router.future future?: Partial>; } /** 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]; /** * Given a Remix Router instance, render the appropriate UI */ export function RouterProvider({ fallbackElement, router, future, }: RouterProviderProps): React.ReactElement { let [state, setStateImpl] = React.useState(router.state); let { v7_startTransition } = future || {}; let setState = React.useCallback( (newState: RouterState) => { if (v7_startTransition && startTransitionImpl) { startTransitionImpl(() => setStateImpl(newState)); } else { setStateImpl(newState); } }, [setStateImpl, v7_startTransition] ); // Need to use a layout effect here so we are subscribed early enough to // pick up on any render-driven redirects/navigations (useEffect/) React.useLayoutEffect(() => router.subscribe(setState), [router, setState]); React.useEffect(() => { warning( fallbackElement == null || !router.future.v7_partialHydration, "`` is deprecated when using " + "`v7_partialHydration`, use a `HydrateFallback` component instead" ); // Only log this once on initial mount // eslint-disable-next-line react-hooks/exhaustive-deps }, []); let navigator = React.useMemo((): Navigator => { return { createHref: router.createHref, encodeLocation: router.encodeLocation, go: (n) => router.navigate(n), push: (to, state, opts) => router.navigate(to, { state, preventScrollReset: opts?.preventScrollReset, }), replace: (to, state, opts) => router.navigate(to, { replace: true, state, preventScrollReset: opts?.preventScrollReset, }), }; }, [router]); let basename = router.basename || "/"; let dataRouterContext = React.useMemo( () => ({ router, navigator, static: false, basename, }), [router, navigator, basename] ); React.useEffect( () => logV6DeprecationWarnings(future, router.future), [router, future] ); // 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