Declarative routing for React web applications
—
Functions for creating router instances programmatically with support for data loading, static generation, and memory-based routing for testing.
Creates a browser router instance with data loading capabilities.
/**
* Creates a browser router with HTML5 history and data loading
* @param routes - Array of route definitions
* @param opts - Router configuration options
* @returns DataRouter instance with full feature support
*/
function createBrowserRouter(
routes: RouteObject[],
opts?: DOMRouterOpts
): DataRouter;
interface DOMRouterOpts {
/** Base URL for all routes */
basename?: string;
/** Custom data loading strategy */
unstable_dataStrategy?: DataStrategyFunction;
/** Dynamic route loading function */
unstable_patchRoutesOnNavigation?: PatchRoutesOnNavigationFunction;
/** Future flags for experimental features */
future?: Partial<Future>;
/** Window object to use (for testing) */
window?: Window;
}
interface DataRouter {
/** Initialize the router and start listening */
initialize(): void;
/** Subscribe to router state changes */
subscribe(fn: RouterSubscriber): () => void;
/** Navigate programmatically */
navigate(to: To, opts?: RouterNavigateOptions): Promise<void>;
/** Fetch data for a route */
fetch(key: string, routeId: string, href: string, opts?: RouterFetchOptions): Promise<void>;
/** Trigger data revalidation */
revalidate(): void;
/** Get data for a specific route */
getRouteData(routeId: string): any;
/** Clean up and dispose router */
dispose(): void;
/** Current router state */
state: RouterState;
}Usage Examples:
import { createBrowserRouter, RouterProvider } from "react-router-dom";
// Basic router setup
const router = createBrowserRouter([
{
path: "/",
element: <Root />,
children: [
{
path: "dashboard",
element: <Dashboard />,
loader: async () => {
const response = await fetch("/api/dashboard");
return response.json();
},
},
{
path: "users/:id",
element: <User />,
loader: async ({ params }) => {
const response = await fetch(`/api/users/${params.id}`);
return response.json();
},
action: async ({ request, params }) => {
const formData = await request.formData();
const response = await fetch(`/api/users/${params.id}`, {
method: "PUT",
body: formData,
});
return response.json();
},
},
],
},
]);
function App() {
return <RouterProvider router={router} />;
}
// Router with options
const router = createBrowserRouter(routes, {
basename: "/my-app",
future: {
unstable_middleware: true,
},
});Creates a hash-based router for compatibility with older browsers and static hosting.
/**
* Creates a hash router for static hosting and legacy browser support
* @param routes - Array of route definitions
* @param opts - Router configuration options
* @returns DataRouter instance using hash-based routing
*/
function createHashRouter(
routes: RouteObject[],
opts?: DOMRouterOpts
): DataRouter;Usage Example:
import { createHashRouter, RouterProvider } from "react-router-dom";
const router = createHashRouter([
{
path: "/",
element: <Home />,
},
{
path: "/about",
element: <About />,
},
]);
// URLs will be: example.com#/ and example.com#/about
function App() {
return <RouterProvider router={router} />;
}Creates an in-memory router perfect for testing and non-browser environments.
/**
* Creates a memory router that stores history in memory
* @param routes - Array of route definitions
* @param opts - Memory router configuration options
* @returns DataRouter instance with in-memory history
*/
function createMemoryRouter(
routes: RouteObject[],
opts?: MemoryRouterOpts
): DataRouter;
interface MemoryRouterOpts {
/** Base URL for all routes */
basename?: string;
/** Custom data loading strategy */
unstable_dataStrategy?: DataStrategyFunction;
/** Dynamic route loading function */
unstable_patchRoutesOnNavigation?: PatchRoutesOnNavigationFunction;
/** Future flags */
future?: Partial<Future>;
/** Initial location entries */
initialEntries?: InitialEntry[];
/** Initial index in history stack */
initialIndex?: number;
}
type InitialEntry = string | Partial<Location>;Usage Examples:
import { createMemoryRouter, RouterProvider } from "react-router-dom";
// Testing setup
const router = createMemoryRouter(
[
{
path: "/",
element: <Home />,
},
{
path: "/users/:id",
element: <User />,
loader: ({ params }) => ({ id: params.id, name: "John" }),
},
],
{
initialEntries: ["/", "/users/123"],
initialIndex: 1, // Start at /users/123
}
);
// Test component
function TestApp() {
return <RouterProvider router={router} />;
}
// React Native or Node.js usage
const serverRouter = createMemoryRouter(routes, {
initialEntries: [request.url],
});Creates a static router for server-side rendering.
/**
* Creates a static router for server-side rendering
* @param routes - Array of route definitions
* @param location - Request location information
* @param opts - Static router options
* @returns DataRouter instance for SSR
*/
function createStaticRouter(
routes: RouteObject[],
location: Partial<Location> | string,
opts?: {
basename?: string;
future?: Partial<Future>;
}
): DataRouter;Usage Example:
import { createStaticRouter, StaticRouterProvider } from "react-router-dom";
// Server-side rendering
export async function render(request: Request) {
const router = createStaticRouter(routes, request.url);
const html = ReactDOMServer.renderToString(
<StaticRouterProvider router={router} context={{}} />
);
return new Response(html, {
headers: { "Content-Type": "text/html" },
});
}Creates a static handler for data loading in SSR environments.
/**
* Creates a static handler for server-side data loading
* @param routes - Array of route definitions
* @param opts - Handler configuration options
* @returns StaticHandler for processing requests
*/
function createStaticHandler(
routes: RouteObject[],
opts?: {
basename?: string;
unstable_dataStrategy?: DataStrategyFunction;
}
): StaticHandler;
interface StaticHandler {
/** Handle a request and return data/redirect */
query(request: Request, opts?: {
requestContext?: unknown;
unstable_dataStrategy?: DataStrategyFunction;
}): Promise<StaticHandlerContext | Response>;
/** Handle a data request */
queryRoute(request: Request, opts?: {
routeId: string;
requestContext?: unknown;
}): Promise<any>;
}
interface StaticHandlerContext {
basename: string;
location: Location;
matches: StaticHandlerMatch[];
loaderData: Record<string, any>;
actionData: Record<string, any> | null;
errors: Record<string, any> | null;
statusCode: number;
loaderHeaders: Record<string, Headers>;
actionHeaders: Record<string, Headers> | null;
activeDeferreds: Record<string, DeferredData> | null;
}Usage Example:
import { createStaticHandler, createStaticRouter } from "react-router-dom";
// Server setup
const routes = [
{
path: "/",
element: <Home />,
loader: () => ({ message: "Welcome!" }),
},
{
path: "/users/:id",
element: <User />,
loader: async ({ params }) => {
const user = await fetchUser(params.id);
return { user };
},
},
];
export async function handleRequest(request: Request) {
const handler = createStaticHandler(routes);
const context = await handler.query(request);
if (context instanceof Response) {
return context; // Redirect response
}
const router = createStaticRouter(routes, context.location);
const html = ReactDOMServer.renderToString(
<StaticRouterProvider router={router} context={context} />
);
return new Response(html, {
status: context.statusCode,
headers: { "Content-Type": "text/html" },
});
}Custom data loading strategy for advanced use cases.
type DataStrategyFunction = (args: DataStrategyFunctionArgs) => Promise<DataStrategyResult>;
interface DataStrategyFunctionArgs {
request: Request;
matches: DataStrategyMatch[];
}
interface DataStrategyMatch {
route: RouteObject;
params: Params;
shouldLoad: boolean;
resolve: (value: any) => void;
reject: (error: any) => void;
}
interface DataStrategyResult {
[routeId: string]: any;
}Function for loading routes dynamically during navigation.
type PatchRoutesOnNavigationFunction = (
args: PatchRoutesOnNavigationFunctionArgs
) => Promise<void> | void;
interface PatchRoutesOnNavigationFunctionArgs {
path: string;
matches: RouteMatch[];
patch: (routeId: string | null, children: RouteObject[]) => void;
}Configuration for experimental features.
interface Future {
/** Enable middleware support */
unstable_middleware: boolean;
/** Enable lazy route discovery */
unstable_lazyRouteDiscovery: boolean;
/** Enable optimistic UI updates */
unstable_optimisticUI: boolean;
}// Organize routes hierarchically
const routes = [
{
path: "/",
element: <Root />,
errorElement: <ErrorBoundary />,
loader: rootLoader,
children: [
{ index: true, element: <Home /> },
{
path: "dashboard",
element: <Dashboard />,
loader: dashboardLoader,
children: [
{ path: "analytics", element: <Analytics /> },
{ path: "settings", element: <Settings /> },
],
},
],
},
];// Add error boundaries at appropriate levels
const routes = [
{
path: "/",
element: <Root />,
errorElement: <RootErrorBoundary />,
children: [
{
path: "admin",
element: <Admin />,
errorElement: <AdminErrorBoundary />,
loader: adminLoader,
},
],
},
];// Implement proper error handling in loaders
const userLoader = async ({ params }) => {
try {
const response = await fetch(`/api/users/${params.id}`);
if (!response.ok) {
throw new Response("User not found", { status: 404 });
}
return response.json();
} catch (error) {
throw new Response("Network error", { status: 500 });
}
};Install with Tessl CLI
npx tessl i tessl/npm-react-router-dom