MENU
Setting Status Codes with StaticRouter
Plain <StaticRouter> no longer takes a "context" attribute, so the old trick of mutating a context object during render to smuggle out a redirect URL or HTTP status code no longer works. The current way to get a real status code out of server-side rendering is to use a data router on the server too: createStaticHandler() runs your loaders/actions and computes the right status for you, and createStaticRouter() + <StaticRouterProvider> render the result.
// routes.js
import { redirect } from "react-router";
function About() { return <h1>About</h1>; }
function Dashboard() { return <h1>Dashboard</h1>; }
function NotFound() {
return (
<div>
<h1>Sorry, can't find that.</h1>
</div>
);
}
export const routes = [
{ path: "/about", Component: About },
{ path: "/dashboard", Component: Dashboard },
// A loader that only ever redirects - the status code is set right here
{ path: "/users", loader: () => redirect("/profiles", { status: 301 }) },
{ path: "/courses", loader: () => redirect("/dashboard", { status: 302 }) },
{ path: "*", Component: NotFound },
];// server.js
import { createStaticHandler, createStaticRouter, StaticRouterProvider } from "react-router";
import { renderToString } from "react-dom/server";
import { routes } from "./routes.js";
const { query, dataRoutes } = createStaticHandler(routes);
export async function handleRequest(request) {
// `request` must be a standard Fetch API Request - adapt your Node
// req/res to one (e.g. with @react-router/node, or your framework's adapter).
const context = await query(request);
// A loader already redirected - its status code (301/302/etc) is baked
// into this Response already, just return it as-is.
if (context instanceof Response) {
return context;
}
const router = createStaticRouter(dataRoutes, context);
const html = renderToString(
<StaticRouterProvider router={router} context={context} />
);
// context.statusCode is 404 automatically when no route matched (or
// whatever a loader threw via `data(..., { status })`); 200 otherwise.
return new Response(`<!doctype html><div id="app">${html}</div>`, {
status: context.statusCode,
headers: { "Content-Type": "text/html" },
});
}