How to Update StaticRouter in React
This article explains how to update and implement
StaticRouter in React applications, specifically focusing
on the transition from React Router v5 to v6 and the modern React Router
v6.4+ data APIs. You will learn how to update your import paths, adapt
to component architecture changes, and transition to the modern
StaticRouterProvider for server-side rendering (SSR).
1. Update the Import Path (React Router v6)
In React Router v5, StaticRouter was imported directly
from the main react-router-dom package. In React Router v6,
this component was moved to a dedicated server entry point to keep
client-side bundles smaller.
To update your import, change it from:
// React Router v5 (Deprecated)
import { StaticRouter } from 'react-router-dom';To the new subpath:
// React Router v6
import { StaticRouter } from 'react-router-dom/server';2. Update Component Structure and Props
React Router v6 replaced the <Switch> component
with <Routes> and changed how children are defined
inside routes. Additionally, the context prop behavior has
changed.
Here is how to update your server-side rendering setup.
Old React Router v5 Implementation:
import React from 'react';
import { renderToString } from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import App from './App';
const context = {};
const html = renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
);Updated React Router v6 Implementation:
In v6, you still pass the location prop, but ensure your
<App /> component uses the new
<Routes> and
<Route element={<Component />} /> syntax
instead of <Switch>.
import React from 'react';
import { renderToString } from 'react-dom/server';
import { StaticRouter } from 'react-router-dom/server';
import App from './App'; // Ensure App uses v6 <Routes>
const html = renderToString(
<StaticRouter location={req.url}>
<App />
</StaticRouter>
);3. Upgrading to StaticRouterProvider (React Router v6.4+)
If you are updating your application to use the modern data APIs
introduced in React Router v6.4 (such as loaders,
actions, and createBrowserRouter), you should
migrate from <StaticRouter> to
<StaticRouterProvider>.
This update requires using @remix-run/router to handle
the server-side request data before rendering.
Step-by-step update:
- Create a server-side handler using
createStaticHandlerandcreateStaticRouter. - Query the active route data based on the incoming request.
- Render the application using
StaticRouterProvider.
Here is the implementation:
import { renderToString } from 'react-dom/server';
import {
createStaticHandler,
createStaticRouter,
StaticRouterProvider,
} from 'react-router-dom/server';
import { routes } from './routes'; // Shared routes array
async function handleServerRequest(req, res) {
const handler = createStaticHandler(routes);
const context = await handler.query(req);
// If the query returns a Response (like a redirect), send it immediately
if (context instanceof Response) {
return res.redirect(context.status, context.headers.get('Location'));
}
const router = createStaticRouter(handler.dataRoutes, context);
const html = renderToString(
<StaticRouterProvider router={router} context={context} />
);
res.send(`<!DOCTYPE html>${html}`);
}