react-router
Version:
Declarative routing for React
1,496 lines (1,490 loc) • 61.1 kB
text/typescript
import { m as HTMLFormMethod, n as FormEncType, o as LoaderFunctionArgs, p as MiddlewareEnabled, c as RouterContextProvider, q as AppLoadContext, r as RouteObject, s as History, t as MaybePromise, u as MapRoutePropertiesFunction, v as Action, L as Location, w as DataRouteMatch, x as Submission, y as RouteData, z as DataStrategyFunction, B as PatchRoutesOnNavigationFunction, E as DataRouteObject, U as UIMatch, T as To, I as Path, P as Params, J as InitialEntry, K as NonIndexRouteObject, O as LazyRouteFunction, Q as IndexRouteObject, V as RouteMatch, W as TrackedPromise } from './routeModules-BRrCYrSL.mjs';
import * as React from 'react';
type unstable_ServerInstrumentation = {
handler?: unstable_InstrumentRequestHandlerFunction;
route?: unstable_InstrumentRouteFunction;
};
type unstable_ClientInstrumentation = {
router?: unstable_InstrumentRouterFunction;
route?: unstable_InstrumentRouteFunction;
};
type unstable_InstrumentRequestHandlerFunction = (handler: InstrumentableRequestHandler) => void;
type unstable_InstrumentRouterFunction = (router: InstrumentableRouter) => void;
type unstable_InstrumentRouteFunction = (route: InstrumentableRoute) => void;
type unstable_InstrumentationHandlerResult = {
status: "success";
error: undefined;
} | {
status: "error";
error: Error;
};
type InstrumentFunction<T> = (handler: () => Promise<unstable_InstrumentationHandlerResult>, info: T) => Promise<void>;
type ReadonlyRequest = {
method: string;
url: string;
headers: Pick<Headers, "get">;
};
type ReadonlyContext = MiddlewareEnabled extends true ? Pick<RouterContextProvider, "get"> : Readonly<AppLoadContext>;
type InstrumentableRoute = {
id: string;
index: boolean | undefined;
path: string | undefined;
instrument(instrumentations: RouteInstrumentations): void;
};
type RouteInstrumentations = {
lazy?: InstrumentFunction<RouteLazyInstrumentationInfo>;
"lazy.loader"?: InstrumentFunction<RouteLazyInstrumentationInfo>;
"lazy.action"?: InstrumentFunction<RouteLazyInstrumentationInfo>;
"lazy.middleware"?: InstrumentFunction<RouteLazyInstrumentationInfo>;
middleware?: InstrumentFunction<RouteHandlerInstrumentationInfo>;
loader?: InstrumentFunction<RouteHandlerInstrumentationInfo>;
action?: InstrumentFunction<RouteHandlerInstrumentationInfo>;
};
type RouteLazyInstrumentationInfo = undefined;
type RouteHandlerInstrumentationInfo = Readonly<{
request: ReadonlyRequest;
params: LoaderFunctionArgs["params"];
unstable_pattern: string;
context: ReadonlyContext;
}>;
type InstrumentableRouter = {
instrument(instrumentations: RouterInstrumentations): void;
};
type RouterInstrumentations = {
navigate?: InstrumentFunction<RouterNavigationInstrumentationInfo>;
fetch?: InstrumentFunction<RouterFetchInstrumentationInfo>;
};
type RouterNavigationInstrumentationInfo = Readonly<{
to: string | number;
currentUrl: string;
formMethod?: HTMLFormMethod;
formEncType?: FormEncType;
formData?: FormData;
body?: any;
}>;
type RouterFetchInstrumentationInfo = Readonly<{
href: string;
currentUrl: string;
fetcherKey: string;
formMethod?: HTMLFormMethod;
formEncType?: FormEncType;
formData?: FormData;
body?: any;
}>;
type InstrumentableRequestHandler = {
instrument(instrumentations: RequestHandlerInstrumentations): void;
};
type RequestHandlerInstrumentations = {
request?: InstrumentFunction<RequestHandlerInstrumentationInfo>;
};
type RequestHandlerInstrumentationInfo = Readonly<{
request: ReadonlyRequest;
context: ReadonlyContext | undefined;
}>;
/**
* A Router instance manages all navigation and data loading/mutations
*/
interface Router$1 {
/**
* @private
* PRIVATE - DO NOT USE
*
* Return the basename for the router
*/
get basename(): RouterInit["basename"];
/**
* @private
* PRIVATE - DO NOT USE
*
* Return the future config for the router
*/
get future(): FutureConfig;
/**
* @private
* PRIVATE - DO NOT USE
*
* Return the current state of the router
*/
get state(): RouterState;
/**
* @private
* PRIVATE - DO NOT USE
*
* Return the routes for this router instance
*/
get routes(): DataRouteObject[];
/**
* @private
* PRIVATE - DO NOT USE
*
* Return the window associated with the router
*/
get window(): RouterInit["window"];
/**
* @private
* PRIVATE - DO NOT USE
*
* Initialize the router, including adding history listeners and kicking off
* initial data fetches. Returns a function to cleanup listeners and abort
* any in-progress loads
*/
initialize(): Router$1;
/**
* @private
* PRIVATE - DO NOT USE
*
* Subscribe to router.state updates
*
* @param fn function to call with the new state
*/
subscribe(fn: RouterSubscriber): () => void;
/**
* @private
* PRIVATE - DO NOT USE
*
* Enable scroll restoration behavior in the router
*
* @param savedScrollPositions Object that will manage positions, in case
* it's being restored from sessionStorage
* @param getScrollPosition Function to get the active Y scroll position
* @param getKey Function to get the key to use for restoration
*/
enableScrollRestoration(savedScrollPositions: Record<string, number>, getScrollPosition: GetScrollPositionFunction, getKey?: GetScrollRestorationKeyFunction): () => void;
/**
* @private
* PRIVATE - DO NOT USE
*
* Navigate forward/backward in the history stack
* @param to Delta to move in the history stack
*/
navigate(to: number): Promise<void>;
/**
* Navigate to the given path
* @param to Path to navigate to
* @param opts Navigation options (method, submission, etc.)
*/
navigate(to: To | null, opts?: RouterNavigateOptions): Promise<void>;
/**
* @private
* PRIVATE - DO NOT USE
*
* Trigger a fetcher load/submission
*
* @param key Fetcher key
* @param routeId Route that owns the fetcher
* @param href href to fetch
* @param opts Fetcher options, (method, submission, etc.)
*/
fetch(key: string, routeId: string, href: string | null, opts?: RouterFetchOptions): Promise<void>;
/**
* @private
* PRIVATE - DO NOT USE
*
* Trigger a revalidation of all current route loaders and fetcher loads
*/
revalidate(): Promise<void>;
/**
* @private
* PRIVATE - DO NOT USE
*
* Utility function to create an href for the given location
* @param location
*/
createHref(location: Location | URL): string;
/**
* @private
* PRIVATE - DO NOT USE
*
* Utility function to URL encode a destination path according to the internal
* history implementation
* @param to
*/
encodeLocation(to: To): Path;
/**
* @private
* PRIVATE - DO NOT USE
*
* Get/create a fetcher for the given key
* @param key
*/
getFetcher<TData = any>(key: string): Fetcher<TData>;
/**
* @internal
* PRIVATE - DO NOT USE
*
* Reset the fetcher for a given key
* @param key
*/
resetFetcher(key: string, opts?: {
reason?: unknown;
}): void;
/**
* @private
* PRIVATE - DO NOT USE
*
* Delete the fetcher for a given key
* @param key
*/
deleteFetcher(key: string): void;
/**
* @private
* PRIVATE - DO NOT USE
*
* Cleanup listeners and abort any in-progress loads
*/
dispose(): void;
/**
* @private
* PRIVATE - DO NOT USE
*
* Get a navigation blocker
* @param key The identifier for the blocker
* @param fn The blocker function implementation
*/
getBlocker(key: string, fn: BlockerFunction): Blocker;
/**
* @private
* PRIVATE - DO NOT USE
*
* Delete a navigation blocker
* @param key The identifier for the blocker
*/
deleteBlocker(key: string): void;
/**
* @private
* PRIVATE DO NOT USE
*
* Patch additional children routes into an existing parent route
* @param routeId The parent route id or a callback function accepting `patch`
* to perform batch patching
* @param children The additional children routes
* @param unstable_allowElementMutations Allow mutation or route elements on
* existing routes. Intended for RSC-usage
* only.
*/
patchRoutes(routeId: string | null, children: RouteObject[], unstable_allowElementMutations?: boolean): void;
/**
* @private
* PRIVATE - DO NOT USE
*
* HMR needs to pass in-flight route updates to React Router
* TODO: Replace this with granular route update APIs (addRoute, updateRoute, deleteRoute)
*/
_internalSetRoutes(routes: RouteObject[]): void;
/**
* @private
* PRIVATE - DO NOT USE
*
* Cause subscribers to re-render. This is used to force a re-render.
*/
_internalSetStateDoNotUseOrYouWillBreakYourApp(state: Partial<RouterState>): void;
/**
* @private
* PRIVATE - DO NOT USE
*
* Internal fetch AbortControllers accessed by unit tests
*/
_internalFetchControllers: Map<string, AbortController>;
}
/**
* State maintained internally by the router. During a navigation, all states
* reflect the "old" location unless otherwise noted.
*/
interface RouterState {
/**
* The action of the most recent navigation
*/
historyAction: Action;
/**
* The current location reflected by the router
*/
location: Location;
/**
* The current set of route matches
*/
matches: DataRouteMatch[];
/**
* Tracks whether we've completed our initial data load
*/
initialized: boolean;
/**
* Tracks whether we should be rendering a HydrateFallback during hydration
*/
renderFallback: boolean;
/**
* Current scroll position we should start at for a new view
* - number -> scroll position to restore to
* - false -> do not restore scroll at all (used during submissions/revalidations)
* - null -> don't have a saved position, scroll to hash or top of page
*/
restoreScrollPosition: number | false | null;
/**
* Indicate whether this navigation should skip resetting the scroll position
* if we are unable to restore the scroll position
*/
preventScrollReset: boolean;
/**
* Tracks the state of the current navigation
*/
navigation: Navigation;
/**
* Tracks any in-progress revalidations
*/
revalidation: RevalidationState;
/**
* Data from the loaders for the current matches
*/
loaderData: RouteData;
/**
* Data from the action for the current matches
*/
actionData: RouteData | null;
/**
* Errors caught from loaders for the current matches
*/
errors: RouteData | null;
/**
* Map of current fetchers
*/
fetchers: Map<string, Fetcher>;
/**
* Map of current blockers
*/
blockers: Map<string, Blocker>;
}
/**
* Data that can be passed into hydrate a Router from SSR
*/
type HydrationState = Partial<Pick<RouterState, "loaderData" | "actionData" | "errors">>;
/**
* Future flags to toggle new feature behavior
*/
interface FutureConfig {
unstable_passThroughRequests: boolean;
}
/**
* Initialization options for createRouter
*/
interface RouterInit {
routes: RouteObject[];
history: History;
basename?: string;
getContext?: () => MaybePromise<RouterContextProvider>;
unstable_instrumentations?: unstable_ClientInstrumentation[];
mapRouteProperties?: MapRoutePropertiesFunction;
future?: Partial<FutureConfig>;
hydrationRouteProperties?: string[];
hydrationData?: HydrationState;
window?: Window;
dataStrategy?: DataStrategyFunction;
patchRoutesOnNavigation?: PatchRoutesOnNavigationFunction;
}
/**
* State returned from a server-side query() call
*/
interface StaticHandlerContext {
basename: Router$1["basename"];
location: RouterState["location"];
matches: RouterState["matches"];
loaderData: RouterState["loaderData"];
actionData: RouterState["actionData"];
errors: RouterState["errors"];
statusCode: number;
loaderHeaders: Record<string, Headers>;
actionHeaders: Record<string, Headers>;
_deepestRenderedBoundaryId?: string | null;
}
/**
* A StaticHandler instance manages a singular SSR navigation/fetch event
*/
interface StaticHandler {
dataRoutes: DataRouteObject[];
query(request: Request, opts?: {
requestContext?: unknown;
filterMatchesToLoad?: (match: DataRouteMatch) => boolean;
skipLoaderErrorBubbling?: boolean;
skipRevalidation?: boolean;
dataStrategy?: DataStrategyFunction<unknown>;
generateMiddlewareResponse?: (query: (r: Request, args?: {
filterMatchesToLoad?: (match: DataRouteMatch) => boolean;
}) => Promise<StaticHandlerContext | Response>) => MaybePromise<Response>;
unstable_normalizePath?: (request: Request) => Path;
}): Promise<StaticHandlerContext | Response>;
queryRoute(request: Request, opts?: {
routeId?: string;
requestContext?: unknown;
dataStrategy?: DataStrategyFunction<unknown>;
generateMiddlewareResponse?: (queryRoute: (r: Request) => Promise<Response>) => MaybePromise<Response>;
unstable_normalizePath?: (request: Request) => Path;
}): Promise<any>;
}
type ViewTransitionOpts = {
currentLocation: Location;
nextLocation: Location;
};
/**
* Subscriber function signature for changes to router state
*/
interface RouterSubscriber {
(state: RouterState, opts: {
deletedFetchers: string[];
newErrors: RouteData | null;
viewTransitionOpts?: ViewTransitionOpts;
flushSync: boolean;
}): void;
}
/**
* Function signature for determining the key to be used in scroll restoration
* for a given location
*/
interface GetScrollRestorationKeyFunction {
(location: Location, matches: UIMatch[]): string | null;
}
/**
* Function signature for determining the current scroll position
*/
interface GetScrollPositionFunction {
(): number;
}
/**
* - "route": relative to the route hierarchy so `..` means remove all segments
* of the current route even if it has many. For example, a `route("posts/:id")`
* would have both `:id` and `posts` removed from the url.
* - "path": relative to the pathname so `..` means remove one segment of the
* pathname. For example, a `route("posts/:id")` would have only `:id` removed
* from the url.
*/
type RelativeRoutingType = "route" | "path";
type BaseNavigateOrFetchOptions = {
preventScrollReset?: boolean;
relative?: RelativeRoutingType;
flushSync?: boolean;
unstable_defaultShouldRevalidate?: boolean;
};
type BaseNavigateOptions = BaseNavigateOrFetchOptions & {
replace?: boolean;
state?: any;
fromRouteId?: string;
viewTransition?: boolean;
unstable_mask?: To;
};
type BaseSubmissionOptions = {
formMethod?: HTMLFormMethod;
formEncType?: FormEncType;
} & ({
formData: FormData;
body?: undefined;
} | {
formData?: undefined;
body: any;
});
/**
* Options for a navigate() call for a normal (non-submission) navigation
*/
type LinkNavigateOptions = BaseNavigateOptions;
/**
* Options for a navigate() call for a submission navigation
*/
type SubmissionNavigateOptions = BaseNavigateOptions & BaseSubmissionOptions;
/**
* Options to pass to navigate() for a navigation
*/
type RouterNavigateOptions = LinkNavigateOptions | SubmissionNavigateOptions;
/**
* Options for a fetch() load
*/
type LoadFetchOptions = BaseNavigateOrFetchOptions;
/**
* Options for a fetch() submission
*/
type SubmitFetchOptions = BaseNavigateOrFetchOptions & BaseSubmissionOptions;
/**
* Options to pass to fetch()
*/
type RouterFetchOptions = LoadFetchOptions | SubmitFetchOptions;
/**
* Potential states for state.navigation
*/
type NavigationStates = {
Idle: {
state: "idle";
location: undefined;
formMethod: undefined;
formAction: undefined;
formEncType: undefined;
formData: undefined;
json: undefined;
text: undefined;
};
Loading: {
state: "loading";
location: Location;
formMethod: Submission["formMethod"] | undefined;
formAction: Submission["formAction"] | undefined;
formEncType: Submission["formEncType"] | undefined;
formData: Submission["formData"] | undefined;
json: Submission["json"] | undefined;
text: Submission["text"] | undefined;
};
Submitting: {
state: "submitting";
location: Location;
formMethod: Submission["formMethod"];
formAction: Submission["formAction"];
formEncType: Submission["formEncType"];
formData: Submission["formData"];
json: Submission["json"];
text: Submission["text"];
};
};
type Navigation = NavigationStates[keyof NavigationStates];
type RevalidationState = "idle" | "loading";
/**
* Potential states for fetchers
*/
type FetcherStates<TData = any> = {
/**
* The fetcher is not calling a loader or action
*
* ```tsx
* fetcher.state === "idle"
* ```
*/
Idle: {
state: "idle";
formMethod: undefined;
formAction: undefined;
formEncType: undefined;
text: undefined;
formData: undefined;
json: undefined;
/**
* If the fetcher has never been called, this will be undefined.
*/
data: TData | undefined;
};
/**
* The fetcher is loading data from a {@link LoaderFunction | loader} from a
* call to {@link FetcherWithComponents.load | `fetcher.load`}.
*
* ```tsx
* // somewhere
* <button onClick={() => fetcher.load("/some/route") }>Load</button>
*
* // the state will update
* fetcher.state === "loading"
* ```
*/
Loading: {
state: "loading";
formMethod: Submission["formMethod"] | undefined;
formAction: Submission["formAction"] | undefined;
formEncType: Submission["formEncType"] | undefined;
text: Submission["text"] | undefined;
formData: Submission["formData"] | undefined;
json: Submission["json"] | undefined;
data: TData | undefined;
};
/**
The fetcher is submitting to a {@link LoaderFunction} (GET) or {@link ActionFunction} (POST) from a {@link FetcherWithComponents.Form | `fetcher.Form`} or {@link FetcherWithComponents.submit | `fetcher.submit`}.
```tsx
// somewhere
<input
onChange={e => {
fetcher.submit(event.currentTarget.form, { method: "post" });
}}
/>
// the state will update
fetcher.state === "submitting"
// and formData will be available
fetcher.formData
```
*/
Submitting: {
state: "submitting";
formMethod: Submission["formMethod"];
formAction: Submission["formAction"];
formEncType: Submission["formEncType"];
text: Submission["text"];
formData: Submission["formData"];
json: Submission["json"];
data: TData | undefined;
};
};
type Fetcher<TData = any> = FetcherStates<TData>[keyof FetcherStates<TData>];
interface BlockerBlocked {
state: "blocked";
reset: () => void;
proceed: () => void;
location: Location;
}
interface BlockerUnblocked {
state: "unblocked";
reset: undefined;
proceed: undefined;
location: undefined;
}
interface BlockerProceeding {
state: "proceeding";
reset: undefined;
proceed: undefined;
location: Location;
}
type Blocker = BlockerUnblocked | BlockerBlocked | BlockerProceeding;
type BlockerFunction = (args: {
currentLocation: Location;
nextLocation: Location;
historyAction: Action;
}) => boolean;
declare const IDLE_NAVIGATION: NavigationStates["Idle"];
declare const IDLE_FETCHER: FetcherStates["Idle"];
declare const IDLE_BLOCKER: BlockerUnblocked;
/**
* Create a router and listen to history POP navigations
*/
declare function createRouter(init: RouterInit): Router$1;
interface CreateStaticHandlerOptions {
basename?: string;
mapRouteProperties?: MapRoutePropertiesFunction;
unstable_instrumentations?: Pick<unstable_ServerInstrumentation, "route">[];
future?: Partial<FutureConfig>;
}
declare function mapRouteProperties(route: RouteObject): Partial<RouteObject> & {
hasErrorBoundary: boolean;
};
declare const hydrationRouteProperties: (keyof RouteObject)[];
/**
* @category Data Routers
*/
interface MemoryRouterOpts {
/**
* Basename path for the application.
*/
basename?: string;
/**
* A function that returns an {@link RouterContextProvider} instance
* which is provided as the `context` argument to client [`action`](../../start/data/route-object#action)s,
* [`loader`](../../start/data/route-object#loader)s and [middleware](../../how-to/middleware).
* This function is called to generate a fresh `context` instance on each
* navigation or fetcher call.
*/
getContext?: RouterInit["getContext"];
/**
* Future flags to enable for the router.
*/
future?: Partial<FutureConfig>;
/**
* Hydration data to initialize the router with if you have already performed
* data loading on the server.
*/
hydrationData?: HydrationState;
/**
* Initial entries in the in-memory history stack
*/
initialEntries?: InitialEntry[];
/**
* Index of `initialEntries` the application should initialize to
*/
initialIndex?: number;
/**
* Array of instrumentation objects allowing you to instrument the router and
* individual routes prior to router initialization (and on any subsequently
* added routes via `route.lazy` or `patchRoutesOnNavigation`). This is
* mostly useful for observability such as wrapping navigations, fetches,
* as well as route loaders/actions/middlewares with logging and/or performance
* tracing. See the [docs](../../how-to/instrumentation) for more information.
*
* ```tsx
* let router = createBrowserRouter(routes, {
* unstable_instrumentations: [logging]
* });
*
*
* let logging = {
* router({ instrument }) {
* instrument({
* navigate: (impl, info) => logExecution(`navigate ${info.to}`, impl),
* fetch: (impl, info) => logExecution(`fetch ${info.to}`, impl)
* });
* },
* route({ instrument, id }) {
* instrument({
* middleware: (impl, info) => logExecution(
* `middleware ${info.request.url} (route ${id})`,
* impl
* ),
* loader: (impl, info) => logExecution(
* `loader ${info.request.url} (route ${id})`,
* impl
* ),
* action: (impl, info) => logExecution(
* `action ${info.request.url} (route ${id})`,
* impl
* ),
* })
* }
* };
*
* async function logExecution(label: string, impl: () => Promise<void>) {
* let start = performance.now();
* console.log(`start ${label}`);
* await impl();
* let duration = Math.round(performance.now() - start);
* console.log(`end ${label} (${duration}ms)`);
* }
* ```
*/
unstable_instrumentations?: unstable_ClientInstrumentation[];
/**
* Override the default data strategy of running loaders in parallel -
* see the [docs](../../how-to/data-strategy) for more information.
*
* ```tsx
* let router = createBrowserRouter(routes, {
* async dataStrategy({
* matches,
* request,
* runClientMiddleware,
* }) {
* const matchesToLoad = matches.filter((m) =>
* m.shouldCallHandler(),
* );
*
* const results: Record<string, DataStrategyResult> = {};
* await runClientMiddleware(() =>
* Promise.all(
* matchesToLoad.map(async (match) => {
* results[match.route.id] = await match.resolve();
* }),
* ),
* );
* return results;
* },
* });
* ```
*/
dataStrategy?: DataStrategyFunction;
/**
* Lazily define portions of the route tree on navigations.
*/
patchRoutesOnNavigation?: PatchRoutesOnNavigationFunction;
}
/**
* Create a new {@link DataRouter} that manages the application path using an
* in-memory [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
* stack. Useful for non-browser environments without a DOM API.
*
* @public
* @category Data Routers
* @mode data
* @param routes Application routes
* @param opts Options
* @param {MemoryRouterOpts.basename} opts.basename n/a
* @param {MemoryRouterOpts.dataStrategy} opts.dataStrategy n/a
* @param {MemoryRouterOpts.future} opts.future n/a
* @param {MemoryRouterOpts.getContext} opts.getContext n/a
* @param {MemoryRouterOpts.hydrationData} opts.hydrationData n/a
* @param {MemoryRouterOpts.initialEntries} opts.initialEntries n/a
* @param {MemoryRouterOpts.initialIndex} opts.initialIndex n/a
* @param {MemoryRouterOpts.unstable_instrumentations} opts.unstable_instrumentations n/a
* @param {MemoryRouterOpts.patchRoutesOnNavigation} opts.patchRoutesOnNavigation n/a
* @returns An initialized {@link DataRouter} to pass to {@link RouterProvider | `<RouterProvider>`}
*/
declare function createMemoryRouter(routes: RouteObject[], opts?: MemoryRouterOpts): Router$1;
/**
* Function signature for client side error handling for loader/actions errors
* and rendering errors via `componentDidCatch`
*/
interface ClientOnErrorFunction {
(error: unknown, info: {
location: Location;
params: Params;
unstable_pattern: string;
errorInfo?: React.ErrorInfo;
}): void;
}
/**
* @category Types
*/
interface RouterProviderProps {
/**
* The {@link DataRouter} instance to use for navigation and data fetching.
*/
router: Router$1;
/**
* The [`ReactDOM.flushSync`](https://react.dev/reference/react-dom/flushSync)
* implementation to use for flushing updates.
*
* You usually don't have to worry about this:
* - The `RouterProvider` exported from `react-router/dom` handles this internally for you
* - If you are rendering in a non-DOM environment, you can import
* `RouterProvider` from `react-router` and ignore this prop
*/
flushSync?: (fn: () => unknown) => undefined;
/**
* An error handler function that will be called for any middleware, loader, action,
* or render errors that are encountered in your application. This is useful for
* logging or reporting errors instead of in the {@link ErrorBoundary} because it's not
* subject to re-rendering and will only run one time per error.
*
* The `errorInfo` parameter is passed along from
* [`componentDidCatch`](https://react.dev/reference/react/Component#componentdidcatch)
* and is only present for render errors.
*
* ```tsx
* <RouterProvider onError=(error, info) => {
* let { location, params, unstable_pattern, errorInfo } = info;
* console.error(error, location, errorInfo);
* reportToErrorService(error, location, errorInfo);
* }} />
* ```
*/
onError?: ClientOnErrorFunction;
/**
* Control whether router state updates are internally wrapped in
* [`React.startTransition`](https://react.dev/reference/react/startTransition).
*
* - When left `undefined`, all state updates are wrapped in
* `React.startTransition`
* - This can lead to buggy behaviors if you are wrapping your own
* navigations/fetchers in `startTransition`.
* - When set to `true`, {@link Link} and {@link Form} navigations will be wrapped
* in `React.startTransition` and router state changes will be wrapped in
* `React.startTransition` and also sent through
* [`useOptimistic`](https://react.dev/reference/react/useOptimistic) to
* surface mid-navigation router state changes to the UI.
* - When set to `false`, the router will not leverage `React.startTransition` or
* `React.useOptimistic` on any navigations or state changes.
*
* For more information, please see the [docs](https://reactrouter.com/explanation/react-transitions).
*/
unstable_useTransitions?: boolean;
}
/**
* Render the UI for the given {@link DataRouter}. This component should
* typically be at the top of an app's element tree.
*
* ```tsx
* import { createBrowserRouter } from "react-router";
* import { RouterProvider } from "react-router/dom";
* import { createRoot } from "react-dom/client";
*
* const router = createBrowserRouter(routes);
* createRoot(document.getElementById("root")).render(
* <RouterProvider router={router} />
* );
* ```
*
* <docs-info>Please note that this component is exported both from
* `react-router` and `react-router/dom` with the only difference being that the
* latter automatically wires up `react-dom`'s [`flushSync`](https://react.dev/reference/react-dom/flushSync)
* implementation. You _almost always_ want to use the version from
* `react-router/dom` unless you're running in a non-DOM environment.</docs-info>
*
*
* @public
* @category Data Routers
* @mode data
* @param props Props
* @param {RouterProviderProps.flushSync} props.flushSync n/a
* @param {RouterProviderProps.onError} props.onError n/a
* @param {RouterProviderProps.router} props.router n/a
* @param {RouterProviderProps.unstable_useTransitions} props.unstable_useTransitions n/a
* @returns React element for the rendered router
*/
declare function RouterProvider({ router, flushSync: reactDomFlushSyncImpl, onError, unstable_useTransitions, }: RouterProviderProps): React.ReactElement;
/**
* @category Types
*/
interface MemoryRouterProps {
/**
* Application basename
*/
basename?: string;
/**
* Nested {@link Route} elements describing the route tree
*/
children?: React.ReactNode;
/**
* Initial entries in the in-memory history stack
*/
initialEntries?: InitialEntry[];
/**
* Index of `initialEntries` the application should initialize to
*/
initialIndex?: number;
/**
* Control whether router state updates are internally wrapped in
* [`React.startTransition`](https://react.dev/reference/react/startTransition).
*
* - When left `undefined`, all router state updates are wrapped in
* `React.startTransition`
* - When set to `true`, {@link Link} and {@link Form} navigations will be wrapped
* in `React.startTransition` and all router state updates are wrapped in
* `React.startTransition`
* - When set to `false`, the router will not leverage `React.startTransition`
* on any navigations or state changes.
*
* For more information, please see the [docs](https://reactrouter.com/explanation/react-transitions).
*/
unstable_useTransitions?: boolean;
}
/**
* A declarative {@link Router | `<Router>`} that stores all entries in memory.
*
* @public
* @category Declarative Routers
* @mode declarative
* @param props Props
* @param {MemoryRouterProps.basename} props.basename n/a
* @param {MemoryRouterProps.children} props.children n/a
* @param {MemoryRouterProps.initialEntries} props.initialEntries n/a
* @param {MemoryRouterProps.initialIndex} props.initialIndex n/a
* @param {MemoryRouterProps.unstable_useTransitions} props.unstable_useTransitions n/a
* @returns A declarative in-memory {@link Router | `<Router>`} for client-side
* routing.
*/
declare function MemoryRouter({ basename, children, initialEntries, initialIndex, unstable_useTransitions, }: MemoryRouterProps): React.ReactElement;
/**
* @category Types
*/
interface NavigateProps {
/**
* The path to navigate to. This can be a string or a {@link Path} object
*/
to: To;
/**
* Whether to replace the current entry in the [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
* stack
*/
replace?: boolean;
/**
* State to pass to the new {@link Location} to store in [`history.state`](https://developer.mozilla.org/en-US/docs/Web/API/History/state).
*/
state?: any;
/**
* How to interpret relative routing in the `to` prop.
* See {@link RelativeRoutingType}.
*/
relative?: RelativeRoutingType;
}
/**
* A component-based version of {@link useNavigate} to use in a
* [`React.Component` class](https://react.dev/reference/react/Component) where
* hooks cannot be used.
*
* It's recommended to avoid using this component in favor of {@link useNavigate}.
*
* @example
* <Navigate to="/tasks" />
*
* @public
* @category Components
* @param props Props
* @param {NavigateProps.relative} props.relative n/a
* @param {NavigateProps.replace} props.replace n/a
* @param {NavigateProps.state} props.state n/a
* @param {NavigateProps.to} props.to n/a
* @returns {void}
*
*/
declare function Navigate({ to, replace, state, relative, }: NavigateProps): null;
/**
* @category Types
*/
interface OutletProps {
/**
* Provides a context value to the element tree below the outlet. Use when
* the parent route needs to provide values to child routes.
*
* ```tsx
* <Outlet context={myContextValue} />
* ```
*
* Access the context with {@link useOutletContext}.
*/
context?: unknown;
}
/**
* Renders the matching child route of a parent route or nothing if no child
* route matches.
*
* @example
* import { Outlet } from "react-router";
*
* export default function SomeParent() {
* return (
* <div>
* <h1>Parent Content</h1>
* <Outlet />
* </div>
* );
* }
*
* @public
* @category Components
* @param props Props
* @param {OutletProps.context} props.context n/a
* @returns React element for the rendered outlet or `null` if no child route matches.
*/
declare function Outlet(props: OutletProps): React.ReactElement | null;
/**
* @category Types
*/
interface PathRouteProps {
/**
* Whether the path should be case-sensitive. Defaults to `false`.
*/
caseSensitive?: NonIndexRouteObject["caseSensitive"];
/**
* The path pattern to match. If unspecified or empty, then this becomes a
* layout route.
*/
path?: NonIndexRouteObject["path"];
/**
* The unique identifier for this route (for use with {@link DataRouter}s)
*/
id?: NonIndexRouteObject["id"];
/**
* A function that returns a promise that resolves to the route object.
* Used for code-splitting routes.
* See [`lazy`](../../start/data/route-object#lazy).
*/
lazy?: LazyRouteFunction<NonIndexRouteObject>;
/**
* The route middleware.
* See [`middleware`](../../start/data/route-object#middleware).
*/
middleware?: NonIndexRouteObject["middleware"];
/**
* The route loader.
* See [`loader`](../../start/data/route-object#loader).
*/
loader?: NonIndexRouteObject["loader"];
/**
* The route action.
* See [`action`](../../start/data/route-object#action).
*/
action?: NonIndexRouteObject["action"];
hasErrorBoundary?: NonIndexRouteObject["hasErrorBoundary"];
/**
* The route shouldRevalidate function.
* See [`shouldRevalidate`](../../start/data/route-object#shouldRevalidate).
*/
shouldRevalidate?: NonIndexRouteObject["shouldRevalidate"];
/**
* The route handle.
*/
handle?: NonIndexRouteObject["handle"];
/**
* Whether this is an index route.
*/
index?: false;
/**
* Child Route components
*/
children?: React.ReactNode;
/**
* The React element to render when this Route matches.
* Mutually exclusive with `Component`.
*/
element?: React.ReactNode | null;
/**
* The React element to render while this router is loading data.
* Mutually exclusive with `HydrateFallback`.
*/
hydrateFallbackElement?: React.ReactNode | null;
/**
* The React element to render at this route if an error occurs.
* Mutually exclusive with `ErrorBoundary`.
*/
errorElement?: React.ReactNode | null;
/**
* The React Component to render when this route matches.
* Mutually exclusive with `element`.
*/
Component?: React.ComponentType | null;
/**
* The React Component to render while this router is loading data.
* Mutually exclusive with `hydrateFallbackElement`.
*/
HydrateFallback?: React.ComponentType | null;
/**
* The React Component to render at this route if an error occurs.
* Mutually exclusive with `errorElement`.
*/
ErrorBoundary?: React.ComponentType | null;
}
/**
* @category Types
*/
interface LayoutRouteProps extends PathRouteProps {
}
/**
* @category Types
*/
interface IndexRouteProps {
/**
* Whether the path should be case-sensitive. Defaults to `false`.
*/
caseSensitive?: IndexRouteObject["caseSensitive"];
/**
* The path pattern to match. If unspecified or empty, then this becomes a
* layout route.
*/
path?: IndexRouteObject["path"];
/**
* The unique identifier for this route (for use with {@link DataRouter}s)
*/
id?: IndexRouteObject["id"];
/**
* A function that returns a promise that resolves to the route object.
* Used for code-splitting routes.
* See [`lazy`](../../start/data/route-object#lazy).
*/
lazy?: LazyRouteFunction<IndexRouteObject>;
/**
* The route middleware.
* See [`middleware`](../../start/data/route-object#middleware).
*/
middleware?: IndexRouteObject["middleware"];
/**
* The route loader.
* See [`loader`](../../start/data/route-object#loader).
*/
loader?: IndexRouteObject["loader"];
/**
* The route action.
* See [`action`](../../start/data/route-object#action).
*/
action?: IndexRouteObject["action"];
hasErrorBoundary?: IndexRouteObject["hasErrorBoundary"];
/**
* The route shouldRevalidate function.
* See [`shouldRevalidate`](../../start/data/route-object#shouldRevalidate).
*/
shouldRevalidate?: IndexRouteObject["shouldRevalidate"];
/**
* The route handle.
*/
handle?: IndexRouteObject["handle"];
/**
* Whether this is an index route.
*/
index: true;
/**
* Child Route components
*/
children?: undefined;
/**
* The React element to render when this Route matches.
* Mutually exclusive with `Component`.
*/
element?: React.ReactNode | null;
/**
* The React element to render while this router is loading data.
* Mutually exclusive with `HydrateFallback`.
*/
hydrateFallbackElement?: React.ReactNode | null;
/**
* The React element to render at this route if an error occurs.
* Mutually exclusive with `ErrorBoundary`.
*/
errorElement?: React.ReactNode | null;
/**
* The React Component to render when this route matches.
* Mutually exclusive with `element`.
*/
Component?: React.ComponentType | null;
/**
* The React Component to render while this router is loading data.
* Mutually exclusive with `hydrateFallbackElement`.
*/
HydrateFallback?: React.ComponentType | null;
/**
* The React Component to render at this route if an error occurs.
* Mutually exclusive with `errorElement`.
*/
ErrorBoundary?: React.ComponentType | null;
}
/**
* @category Types
*/
type RouteProps = PathRouteProps | LayoutRouteProps | IndexRouteProps;
/**
* Configures an element to render when a pattern matches the current location.
* It must be rendered within a {@link Routes} element. Note that these routes
* do not participate in data loading, actions, code splitting, or any other
* route module features.
*
* @example
* // Usually used in a declarative router
* function App() {
* return (
* <BrowserRouter>
* <Routes>
* <Route index element={<StepOne />} />
* <Route path="step-2" element={<StepTwo />} />
* <Route path="step-3" element={<StepThree />} />
* </Routes>
* </BrowserRouter>
* );
* }
*
* // But can be used with a data router as well if you prefer the JSX notation
* const routes = createRoutesFromElements(
* <>
* <Route index loader={step1Loader} Component={StepOne} />
* <Route path="step-2" loader={step2Loader} Component={StepTwo} />
* <Route path="step-3" loader={step3Loader} Component={StepThree} />
* </>
* );
*
* const router = createBrowserRouter(routes);
*
* function App() {
* return <RouterProvider router={router} />;
* }
*
* @public
* @category Components
* @param props Props
* @param {PathRouteProps.action} props.action n/a
* @param {PathRouteProps.caseSensitive} props.caseSensitive n/a
* @param {PathRouteProps.Component} props.Component n/a
* @param {PathRouteProps.children} props.children n/a
* @param {PathRouteProps.element} props.element n/a
* @param {PathRouteProps.ErrorBoundary} props.ErrorBoundary n/a
* @param {PathRouteProps.errorElement} props.errorElement n/a
* @param {PathRouteProps.handle} props.handle n/a
* @param {PathRouteProps.HydrateFallback} props.HydrateFallback n/a
* @param {PathRouteProps.hydrateFallbackElement} props.hydrateFallbackElement n/a
* @param {PathRouteProps.id} props.id n/a
* @param {PathRouteProps.index} props.index n/a
* @param {PathRouteProps.lazy} props.lazy n/a
* @param {PathRouteProps.loader} props.loader n/a
* @param {PathRouteProps.path} props.path n/a
* @param {PathRouteProps.shouldRevalidate} props.shouldRevalidate n/a
* @returns {void}
*/
declare function Route(props: RouteProps): React.ReactElement | null;
/**
* @category Types
*/
interface RouterProps {
/**
* The base path for the application. This is prepended to all locations
*/
basename?: string;
/**
* Nested {@link Route} elements describing the route tree
*/
children?: React.ReactNode;
/**
* The location to match against. Defaults to the current location.
* This can be a string or a {@link Location} object.
*/
location: Partial<Location> | string;
/**
* The type of navigation that triggered this `location` change.
* Defaults to {@link NavigationType.Pop}.
*/
navigationType?: Action;
/**
* The navigator to use for navigation. This is usually a history object
* or a custom navigator that implements the {@link Navigator} interface.
*/
navigator: Navigator;
/**
* Whether this router is static or not (used for SSR). If `true`, the router
* will not be reactive to location changes.
*/
static?: boolean;
/**
* Control whether router state updates are internally wrapped in
* [`React.startTransition`](https://react.dev/reference/react/startTransition).
*
* - When left `undefined`, all router state updates are wrapped in
* `React.startTransition`
* - When set to `true`, {@link Link} and {@link Form} navigations will be wrapped
* in `React.startTransition` and all router state updates are wrapped in
* `React.startTransition`
* - When set to `false`, the router will not leverage `React.startTransition`
* on any navigations or state changes.
*
* For more information, please see the [docs](https://reactrouter.com/explanation/react-transitions).
*/
unstable_useTransitions?: boolean;
}
/**
* Provides location context for the rest of the app.
*
* Note: You usually won't render a `<Router>` directly. Instead, you'll render a
* router that is more specific to your environment such as a {@link BrowserRouter}
* in web browsers or a {@link ServerRouter} for server rendering.
*
* @public
* @category Declarative Routers
* @mode declarative
* @param props Props
* @param {RouterProps.basename} props.basename n/a
* @param {RouterProps.children} props.children n/a
* @param {RouterProps.location} props.location n/a
* @param {RouterProps.navigationType} props.navigationType n/a
* @param {RouterProps.navigator} props.navigator n/a
* @param {RouterProps.static} props.static n/a
* @param {RouterProps.unstable_useTransitions} props.unstable_useTransitions n/a
* @returns React element for the rendered router or `null` if the location does
* not match the {@link props.basename}
*/
declare function Router({ basename: basenameProp, children, location: locationProp, navigationType, navigator, static: staticProp, unstable_useTransitions, }: RouterProps): React.ReactElement | null;
/**
* @category Types
*/
interface RoutesProps {
/**
* Nested {@link Route} elements
*/
children?: React.ReactNode;
/**
* The {@link Location} to match against. Defaults to the current location.
*/
location?: Partial<Location> | string;
}
/**
* Renders a branch of {@link Route | `<Route>`s} that best matches the current
* location. Note that these routes do not participate in [data loading](../../start/framework/route-module#loader),
* [`action`](../../start/framework/route-module#action), code splitting, or
* any other [route module](../../start/framework/route-module) features.
*
* @example
* import { Route, Routes } from "react-router";
*
* <Routes>
* <Route index element={<StepOne />} />
* <Route path="step-2" element={<StepTwo />} />
* <Route path="step-3" element={<StepThree />} />
* </Routes>
*
* @public
* @category Components
* @param props Props
* @param {RoutesProps.children} props.children n/a
* @param {RoutesProps.location} props.location n/a
* @returns React element for the rendered routes or `null` if no route matches
*/
declare function Routes({ children, location, }: RoutesProps): React.ReactElement | null;
interface AwaitResolveRenderFunction<Resolve = any> {
(data: Awaited<Resolve>): React.ReactNode;
}
/**
* @category Types
*/
interface AwaitProps<Resolve> {
/**
* When using a function, the resolved value is provided as the parameter.
*
* ```tsx [2]
* <Await resolve={reviewsPromise}>
* {(resolvedReviews) => <Reviews items={resolvedReviews} />}
* </Await>
* ```
*
* When using React elements, {@link useAsyncValue} will provide the
* resolved value:
*
* ```tsx [2]
* <Await resolve={reviewsPromise}>
* <Reviews />
* </Await>
*
* function Reviews() {
* const resolvedReviews = useAsyncValue();
* return <div>...</div>;
* }
* ```
*/
children: React.ReactNode | AwaitResolveRenderFunction<Resolve>;
/**
* The error element renders instead of the `children` when the [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
* rejects.
*
* ```tsx
* <Await
* errorElement={<div>Oops</div>}
* resolve={reviewsPromise}
* >
* <Reviews />
* </Await>
* ```
*
* To provide a more contextual error, you can use the {@link useAsyncError} in a
* child component
*
* ```tsx
* <Await
* errorElement={<ReviewsError />}
* resolve={reviewsPromise}
* >
* <Reviews />
* </Await>
*
* function ReviewsError() {
* const error = useAsyncError();
* return <div>Error loading reviews: {error.message}</div>;
* }
* ```
*
* If you do not provide an `errorElement`, the rejected value will bubble up
* to the nearest route-level [`ErrorBoundary`](../../start/framework/route-module#errorboundary)
* and be accessible via the {@link useRouteError} hook.
*/
errorElement?: React.ReactNode;
/**
* Takes a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
* returned from a [`loader`](../../start/framework/route-module#loader) to be
* resolved and rendered.
*
* ```tsx
* import { Await, useLoaderData } from "react-router";
*
* export async function loader() {
* let reviews = getReviews(); // not awaited
* let book = await getBook();
* return {
* book,
* reviews, // this is a promise
* };
* }
*
* export default function Book() {
* const {
* book,
* reviews, // this is the same promise
* } = useLoaderData();
*
* return (
* <div>
* <h1>{book.title}</h1>
* <p>{book.description}</p>
* <React.Suspense fallback={<ReviewsSkeleton />}>
* <Await
* // and is the promise we pass to Await
* resolve={reviews}
* >
* <Reviews />
* </Await>
* </React.Suspense>
* </div>
* );
* }
* ```
*/
resolve: Resolve;
}
/**
* Used to render promise values with automatic error handling.
*
* **Note:** `<Await>` expects to be rendered inside a [`<React.Suspense>`](https://react.dev/reference/react/Suspense)
*
* @exa