react-router
Advanced tools
Changelog
v7.8.0
Date: 2025-08-07
loaderData
valuesEver noticed the discrepancies in loader data values handed to you by the framework? Like, we call it loaderData
in your component props, but then match.data
in your matches? Yeah, us too - as well as some keen-eyed React Router users who raised this in a proposal. We've added new loaderData
fields alongside existing data
fields in a few lingering spots to align with the loaderData
naming used in the new Route.*
APIs.
The biggest set of changes in 7.8.0
are to the unstable_middleware
API's as we move closer to stabilizing them. If you've adopted the middleware APIs for early testing, please read the middleware changes below carefully. We hope to stabilize these soon so please let us know of any feedback you have on the API's in their current state!
react-router
- Add nonce
prop to Links
& PrefetchPageLinks
(#14048)react-router
- Add loaderData
arguments/properties alongside existing data
arguments/properties to provide consistency and clarity between loaderData
and actionData
across the board (#14047)
Route.MetaArgs
, Route.MetaMatch
, MetaArgs
, MetaMatch
, Route.ComponentProps.matches
, UIMatch
@deprecated
warnings have been added to the existing data
properties to point users to new loaderData
properties, in preparation for removing the data
properties in a future major releasereact-router
- Prevent "Did not find corresponding fetcher result" console error when navigating during a fetcher.submit
revalidation (#14114)
react-router
- Switch Lazy Route Discovery manifest URL generation to use a standalone URLSearchParams
instance instead of URL.searchParams
to avoid a major performance bottleneck in Chrome (#14084)
react-router
- Adjust internal RSC usage of React.use
to avoid Webpack compilation errors when using React 18 (#14113)
react-router
- Remove dependency on @types/node
in TypeScript declaration files (#14059)
react-router
- Fix types for UIMatch
to reflect that the loaderData
/data
properties may be undefined
(#12206)
When an ErrorBoundary
is being rendered, not all active matches will have loader data available, since it may have been their loader
that threw to trigger the boundary
The UIMatch.data
type was not correctly handing this and would always reflect the presence of data, leading to the unexpected runtime errors when an ErrorBoundary
was rendered
â ď¸ This may cause some type errors to show up in your code for unguarded match.data
accesses - you should properly guard for undefined
values in those scenarios.
// app/root.tsx
export function loader() {
someFunctionThatThrows(); // â Throws an Error
return { title: "My Title" };
}
export function Layout({ children }: { children: React.ReactNode }) {
let matches = useMatches();
let rootMatch = matches[0] as UIMatch<Awaited<ReturnType<typeof loader>>>;
// ^ rootMatch.data is currently incorrectly typed here, so TypeScript does
// not complain if you do the following which throws an error at runtime:
let { title } = rootMatch.data; // đĽ
return <html>...</html>;
}
@react-router/dev
- Fix rename without mkdir in Vite plugin (#14105)
â ď¸ Unstable features are not recommended for production use
RSC
react-router
- Fix Data Mode issue where routes that return false
from shouldRevalidate
would be replaced by an <Outlet />
(#14071)react-router
- Proxy server action side-effect redirects from actions for document and callServer
requests (#14131)Middleware
react-router
- Change the unstable_getContext
signature on RouterProvider
, HydratedRouter
, and unstable_RSCHydratedRouter
so that it returns an unstable_RouterContextProvider
instance instead of a Map
used to construct the instance internally (#14097)
unstable_getContext
propreact-router
- Run client middleware on client navigations even if no loaders exist (#14106)
react-router
- Convert internal middleware implementations to use the new unstable_generateMiddlewareResponse
API (#14103)
react-router
- Ensure resource route errors go through handleError
w/middleware enabled (#14078)
react-router
- Propagate returned Response
from server middleware if next
wasn't called (#14093)
react-router
- Allow server middlewares to return data()
values which will be converted into a Response
(#14093, #14128)
react-router
- Update middleware error handling so that the next
function never throws and instead handles any middleware errors at the proper ErrorBoundary
and returns the Response
up through the ancestor next
function (#14118)
next
calls in try
/catch
you should be able to remove thosereact-router
- Bubble client-side middleware errors prior to next
to the appropriate ancestor error boundary (#14138)
react-router
- When middleware is enabled, make the context
parameter read-only (Readonly<unstable_RouterContextProvider>
) so that TypeScript will not allow you to write arbitrary fields to it in loaders, actions, or middleware. (#14097)
react-router
- Rename and alter the signature/functionality of the unstable_respond
API in staticHandler.query
/staticHandler.queryRoute
(#14103)
This only impacts users using createStaticHandler()
for manual data loading during non-Framework Mode SSR
The API has been renamed to unstable_generateMiddlewareResponse
for clarity
The main functional change is that instead of running the loaders/actions before calling unstable_respond
and handing you the result, we now pass a query
/queryRoute
function as a parameter and you execute the loaders/actions inside your callback, giving you full access to pre-processing and error handling
The query
version of the API now has a signature of (query: (r: Request) => Promise<StaticHandlerContext | Response>) => Promise<Response>
The queryRoute
version of the API now has a signature of (queryRoute: (r: Request) => Promise<Response>) => Promise<Response>
This allows for more advanced usages such as running logic before/after calling query
and direct error handling of errors thrown from query
â ď¸ This is a breaking change if you've adopted the staticHandler
unstable_respond
API
let response = await staticHandler.query(request, {
requestContext: new unstable_RouterContextProvider(),
async unstable_generateMiddlewareResponse(query) {
try {
// At this point we've run middleware top-down so we need to call the
// handlers and generate the Response to bubble back up the middleware
let result = await query(request);
if (isResponse(result)) {
return result; // Redirects, etc.
}
return await generateHtmlResponse(result);
} catch (error: unknown) {
return generateErrorResponse(error);
}
},
});
@react-router/{architect,cloudflare,express,node}
- Change the getLoadContext
signature (type GetLoadContextFunction
) when future.unstable_middleware
is enabled so that it returns an unstable_RouterContextProvider
instance instead of a Map
used to construct the instance internally (#14097)
type unstable_InitialContext
exportgetLoadContext
docs for more informationgetLoadContext
functioncreate-react-router
react-router
@react-router/architect
@react-router/cloudflare
@react-router/dev
@react-router/express
@react-router/fs-routes
@react-router/node
@react-router/remix-config-routes-adapter
@react-router/serve
Full Changelog: v7.7.1...v7.8.0