NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #1611 most downloaded on npm
Declarative routing for React
Last release 2 days ago
15 Sep 2026
Ships on a steady schedule
a new release about every 2 weeks
Nearly every release is documented
notes for 60 of the last 60 stable releases
1 version withdrawn
withdrawn after publishing
13 years old
1186 releases · first in 2014
Nothing published for this version
See the changelog for release notes: https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v6213
See the changelog for release notes: https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v6213
unstable_ prefix from Blocker/BlockerFunction types (#11187)Date: 2024-01-18
NavLink isPending when a basename is used (#11195)unstable_ prefix from Blocker/BlockerFunction types (#11187)Full Changelog: v6.21.2...v6.21.3
One column per quarter.
Nothing published for this version
See the changelog for release notes: https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v6212
See the changelog for release notes: https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v6212
@remix-run/router@1.14.2Date: 2024-01-11
useId for internal fetcher keys when available (#11166)Full Changelog: v6.21.1...v6.21.2
Nothing published for this version
See the changelog for release notes: https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v6211
See the changelog for release notes: https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v6211
route.lazy not working correctly on initial SPA load when v7_partialHydration is specified (#11121)@remix-run/router@1.14.1Date: 2023-12-21
route.lazy not working correctly on initial SPA load when v7_partialHydration is specified (#11121)submitting phase (#11102)resolveTo (#11097)Full Changelog: v6.21.0...v6.21.1
Nothing published for this version
See the changelog for release notes: https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v6210
See the changelog for release notes: https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v6210
Add a new future.v7_relativeSplatPath flag to implement a breaking bug fix to relative routing when inside a splat route. (#11087)
This fix was originally added in #10983 and was later reverted in #11078 because it was determined that a large number of existing applications were relying on the buggy behavior (see #11052)
The Bug
The buggy behavior is that without this flag, the default behavior when resolving relative paths is to ignore any splat (*) portion of the current route path.
The Background
This decision was originally made thinking that it would make the concept of nested different sections of your apps in <Routes> easier if relative routing would replace the current splat:
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="dashboard/*" element={<Dashboard />} />
</Routes>
</BrowserRouter>
Any paths like /dashboard, /dashboard/team, /dashboard/projects will match the Dashboard route. The dashboard component itself can then render nested <Routes>:
function Dashboard() {
return (
<div>
<h2>Dashboard</h2>
<nav>
<Link to="/">Dashboard Home</Link>
<Link to="team">Team</Link>
<Link to="projects">Projects</Link>
</nav>
<Routes>
<Route path="/" element={<DashboardHome />} />
<Route path="team" element={<DashboardTeam />} />
<Route path="projects" element={<DashboardProjects />} />
</Routes>
</div>
);
}
Now, all links and route paths are relative to the router above them. This makes code splitting and compartmentalizing your app really easy. You could render the Dashboard as its own independent app, or embed it into your large app without making any changes to it.
The Problem
The problem is that this concept of ignoring part of a path breaks a lot of other assumptions in React Router - namely that "." always means the current location pathname for that route. When we ignore the splat portion, we start getting invalid paths when using ".":
// If we are on URL /dashboard/team, and we want to link to /dashboard/team:
function DashboardTeam() {
// ❌ This is broken and results in <a href="/dashboard">
return <Link to=".">A broken link to the Current URL</Link>;
// ✅ This is fixed but super unintuitive since we're already at /dashboard/team!
return <Link to="./team">A broken link to the Current URL</Link>;
}
We've also introduced an issue that we can no longer move our DashboardTeam component around our route hierarchy easily - since it behaves differently if we're underneath a non-splat route, such as /dashboard/:widget. Now, our "." links will, properly point to ourself inclusive of the dynamic param value so behavior will break from it's corresponding usage in a /dashboard/* route.
Even worse, consider a nested splat route configuration:
<BrowserRouter>
<Routes>
<Route path="dashboard">
<Route path="*" element={<Dashboard />} />
</Route>
</Routes>
</BrowserRouter>
Now, a <Link to="."> and a <Link to=".."> inside the Dashboard component go to the same place! That is definitely not correct!
Another common issue arose in Data Routers (and Remix) where any <Form> should post to it's own route action if you the user doesn't specify a form action:
let router = createBrowserRouter({
path: "/dashboard",
children: [
{
path: "*",
action: dashboardAction,
Component() {
// ❌ This form is broken! It throws a 405 error when it submits because
// it tries to submit to /dashboard (without the splat value) and the parent
// `/dashboard` route doesn't have an action
return <Form method="post">...</Form>;
},
},
],
});
This is just a compounded issue from the above because the default location for a Form to submit to is itself (".") - and if we ignore the splat portion, that now resolves to the parent route.
The Solution
If you are leveraging this behavior, it's recommended to enable the future flag, move your splat to it's own route, and leverage ../ for any links to "sibling" pages:
<BrowserRouter>
<Routes>
<Route path="dashboard">
<Route index path="*" element={<Dashboard />} />
</Route>
</Routes>
</BrowserRouter>
function Dashboard() {
return (
<div>
<h2>Dashboard</h2>
<nav>
<Link to="..">Dashboard Home</Link>
<Link to="../team">Team</Link>
<Link to="../projects">Projects</Link>
</nav>
<Routes>
<Route path="/" element={<DashboardHome />} />
<Route path="team" element={<DashboardTeam />} />
<Route path="projects" element={<DashboardProjects />} />
</Router>
</div>
);
}
This way, . means "the full current pathname for my route" in all cases (including static, dynamic, and splat routes) and .. always means "my parents pathname".
@remix-run/router@1.14.0Date: 2023-12-13
future.v7_relativeSplatPathWe fixed a splat route path-resolution bug in 6.19.0, but later determined a large number of applications were relying on the buggy behavior, so we reverted the fix in 6.20.1 (see #10983, #11052, #11078).
The buggy behavior is that the default behavior when resolving relative paths inside a splat route would ignore any splat (*) portion of the current route path. When the future flag is enabled, splat portions are included in relative path logic within splat routes.
For more information, please refer to the useResolvedPath docs and/or the detailed changelog entry.
We added a new future.v7_partialHydration future flag for the @remix-run/router that enables partial hydration of a data router when Server-Side Rendering. This allows you to provide hydrationData.loaderData that has values for some initially matched route loaders, but not all. When this flag is enabled, the router will call loader functions for routes that do not have hydration loader data during router.initialize(), and it will render down to the deepest provided HydrateFallback (up to the first route without hydration data) while it executes the unhydrated routes. (#11033)
future.v7_relativeSplatPath flag to implement a breaking bug fix to relative routing when inside a splat route. (#11087)future.v7_partialHydration future flag that enables partial hydration of a data router when Server-Side Rendering (#11033)ErrorBoundary's (#11071)loader/action functions (#11061)relative="path" issue when rendering Link/NavLink outside of matched routes (#11062)Full Changelog: v6.20.1...v6.21.0
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
See the changelog for release notes: https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v6201
See the changelog for release notes: https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v6201
useResolvedPath fix for splat routes due to a large number of applications that were relying on the buggy behavior (see https://github.com/remix-run/react-router/issues/11052#issuecomment-1836589329). We plan to re-introduce this fix behind a future flag in the next minor version. (#11078)@remix-run/router@1.13.1Date: 2023-12-01
useResolvedPath fix for splat routes due to a large number of applications that were relying on the buggy behavior (see #11052) (#11078)
6.19.0 and 6.20.0. If you are upgrading from 6.18.0 or earlier, you would not have been impacted by this fix.Full Changelog: v6.20.0...v6.20.1
Nothing published for this version
See the changelog for release notes: https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v6200
See the changelog for release notes: https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v6200
PathParam type from the public API (#10719)resolveTo in splat routes (#11045)
getPathContributingMatchesUNSAFE_getPathContributingMatches export from @remix-run/router since we no longer need this in the react-router/react-router-dom layers@remix-run/router@1.13.0Date: 2023-11-22
[!WARNING] Please use version
6.20.1or later instead of6.20.0. We discovered that a large number of apps were relying on buggy behavior that was fixed in this release (#11045). We reverted the fix in6.20.1and will be re-introducing it behind a future flag in a subsequent release. See #11052 for more details.
PathParam type from the public API (#10719)v7_fetcherPersist is enabled (#11044)resolveTo path resolution in splat routes (#11045)
getPathContributingMatchesUNSAFE_getPathContributingMatches export from @remix-run/router since we no longer need this in the react-router/react-router-dom layersFull Changelog: v6.19.0...v6.20.0
Nothing published for this version
See the changelog for release notes: https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v6190
See the changelog for release notes: https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v6190
unstable_flushSync option to useNavigate/useSumbit/fetcher.load/fetcher.submit to opt-out of React.startTransition and into ReactDOM.flushSync for state updates (#11005)unstable_ prefix from the useBlocker hook as it's been in use for enough time that we are confident in the API. We do not plan to remove the prefix from unstable_usePrompt due to differences in how browsers handle window.confirm that prevent React Router from guaranteeing consistent/correct behavior. (#10991)Fix useActionData so it returns proper contextual action data and not any action data in the tree (#11023)
Fix bug in useResolvedPath that would cause useResolvedPath(".") in a splat route to lose the splat portion of the URL path. (#10983)
"." paths inside a splat route which incorrectly dropped the splat portion of the URL. If you are relative routing via "." inside a splat route in your application you should double check that your logic is not relying on this buggy behavior and update accordingly.Updated dependencies:
@remix-run/router@1.12.0Date: 2023-11-16
[!WARNING] Please use version
6.20.1or later instead of6.19.0. We discovered that a large number of apps were relying on buggy behavior that was fixed in this release (#10983). We reverted the fix in6.20.1and will be re-introducing it behind a future flag in a subsequent release. See #11052 for more details.
unstable_flushSync APIThis release brings a new unstable_flushSync option to the imperative APIs (useSubmit, useNavigate, fetcher.submit, fetcher.load) to let users opt-into synchronous DOM updates for pending/optimistic UI.
function handleClick() {
submit(data, { flushSync: true });
// Everything is flushed to the DOM so you can focus/scroll to your pending/optimistic UI
setFocusAndOrScrollToNewlyAddedThing();
}
unstable_flushSync option to useNavigate/useSubmit/fetcher.load/fetcher.submit to opt-out of React.startTransition and into ReactDOM.flushSync for state updates (#11005)unstable_ prefix from the useBlocker hook as it's been in use for enough time that we are confident in the API (#10991)
unstable_usePrompt due to differences in how browsers handle window.confirm that prevent React Router from guaranteeing consistent/correct behaviorFix useActionData so it returns proper contextual action data and not any action data in the tree (#11023)
Fix bug in useResolvedPath that would cause useResolvedPath(".") in a splat route to lose the splat portion of the URL path. (#10983)
"." paths inside a splat route which incorrectly dropped the splat portion of the URL. If you are relative routing via "." inside a splat route in your application you should double check that your logic is not relying on this buggy behavior and update accordingly.Fix issue where a changing fetcher key in a useFetcher that remains mounted wasn't getting picked up (#11009)
Fix useFormAction which was incorrectly inheriting the ?index query param from child route action submissions (#11025)
Fix NavLink active logic when to location has a trailing slash (#10734)
Fix types so unstable_usePrompt can accept a BlockerFunction in addition to a boolean (#10991)
Fix relative="path" bug where relative path calculations started from the full location pathname, instead of from the current contextual route pathname. (#11006)
<Route path="/a">
<Route path="/b" element={<Component />}>
<Route path="/c" />
</Route>
</Route>;
function Component() {
return (
<>
{/* This is now correctly relative to /a/b, not /a/b/c */}
<Link to=".." relative="path" />
<Outlet />
</>
);
}
Full Changelog: 6.18.0...6.19.0
Nothing published for this version
Per this RFC, we've introduced some new APIs that give you more granular control over your fetcher behaviors.
Per this RFC, we've introduced some new APIs that give you more granular control over your fetcher behaviors. (#10960)
useFetcher({ key: string }), which allows you to access the same fetcher instance from different components in your application without prop-drillinguseFetchers so that they can be looked up by keyForm and useSumbit now support optional navigate/fetcherKey props/params to allow kicking off a fetcher submission under the hood with an optionally user-specified key
<Form method="post" navigate={false} fetcherKey="my-key">submit(data, { method: "post", navigate: false, fetcherKey: "my-key" })useFetchers() or useFetcher({ key }) to look it up elsewherefuture.v7_fetcherPersist)Per the same RFC as above, we've introduced a new future.v7_fetcherPersist flag that allows you to opt-into the new fetcher persistence/cleanup behavior. Instead of being immediately cleaned up on unmount, fetchers will persist until they return to an idle state. This makes pending/optimistic UI much easier in scenarios where the originating fetcher needs to unmount. (#10962)
useFetchers() API was always supposed to only reflect in-flight fetcher information for pending/optimistic UI -- it was not intended to reflect fetcher data or hang onto fetchers after they returned to an idle stateuseFetchers() after completion - they served no purpose in there since you can access the data via useFetcher().dataidle state
useFetchers while in-flight so you can still access pending/optimistic data after unmountkey, then it's result will be processed, even if the originating fetcher was unmountedmatchPath (#10768)future prop on BrowserRouter, HashRouter and MemoryRouter so that it accepts a Partial<FutureConfig> instead of requiring all flags to be included (#10962)router.getFetcher/router.deleteFetcher type definitions which incorrectly specified key as an optional parameter (#10960)Full Changelog: 6.17.0...6.18.0
future prop on BrowserRouter, HashRouter and MemoryRouter so that it accepts a Partial<FutureConfig> instead of requiring all flags to be included. (#10962)@remix-run/router@1.11.0Nothing published for this version
Nothing published for this version
We're excited to release experimental support for the the View Transitions API in React Router! You can now trigger navigational DOM updates to be wra
We're excited to release experimental support for the the View Transitions API in React Router! You can now trigger navigational DOM updates to be wrapped in document.startViewTransition to enable CSS animated transitions on SPA navigations in your application. (#10916)
The simplest approach to enabling a View Transition in your React Router app is via the new <Link unstable_viewTransition> prop. This will cause the navigation DOM update to be wrapped in document.startViewTransition which will enable transitions for the DOM update. Without any additional CSS styles, you'll get a basic cross-fade animation for your page.
If you need to apply more fine-grained styles for your animations, you can leverage the unstable_useViewTransitionState hook which will tell you when a transition is in progress and you can use that to apply classes or styles:
function ImageLink(to, src, alt) {
const isTransitioning = unstable_useViewTransitionState(to);
return (
<Link to={to} unstable_viewTransition>
<img
src={src}
alt={alt}
style={{
viewTransitionName: isTransitioning ? "image-expand" : "",
}}
/>
</Link>
);
}
You can also use the <NavLink unstable_viewTransition> shorthand which will manage the hook usage for you and automatically add a transitioning class to the <a> during the transition:
a.transitioning img {
view-transition-name: "image-expand";
}
<NavLink to={to} unstable_viewTransition>
<img src={src} alt={alt} />
</NavLink>
For an example usage of View Transitions, check out our fork of the awesome Astro Records demo.
For more information on using the View Transitions API, please refer to the Smooth and simple transitions with the View Transitions API guide from the Google Chrome team.
ScrollRestoration when sessionStorage is unavailable (#10848)RouterProvider future prop type to be a Partial<FutureConfig> so that not all flags must be specified (#10900)ErrorResponse type to avoid leaking internal field (#10876)Full Changelog: 6.16.0...6.17.0
RouterProvider future prop type to be a Partial<FutureConfig> so that not all flags must be specified (#10900)@remix-run/router@1.10.0Nothing published for this version
Nothing published for this version
Nothing published for this version
To do this in Remix v2 without introducing breaking changes in React Router v6, we have added generics to a number of shared types. These continue to…
any with unknown on exposed typings for user-provided data. To do this in Remix v2 without introducing breaking changes in React Router v6, we have added generics to a number of shared types. These continue to default to any in React Router and are overridden with unknown in Remix. In React Router v7 we plan to move these to unknown as a breaking change. (#10843)
Location now accepts a generic for the location.state valueActionFunctionArgs/ActionFunction/LoaderFunctionArgs/LoaderFunction now accept a generic for the context parameter (only used in SSR usages via createStaticHandler)useMatches (now exported as UIMatch) accepts generics for match.data and match.handle - both of which were already set to unknown@private class export ErrorResponse to an UNSAFE_ErrorResponseImpl export since it is an implementation detail and there should be no construction of ErrorResponse instances in userland. This frees us up to export a type ErrorResponse which correlates to an instance of the class via InstanceType. Userland code should only ever be using ErrorResponse as a type and should be type-narrowing via isRouteErrorResponse. (#10811)ShouldRevalidateFunctionArgs interface (#10797)_isFetchActionRedirect, _hasFetcherDoneAnything) (#10715)query/queryRoute calls (#10793)route.lazy routes (#10778)actionResult on the arguments object passed to shouldRevalidate (#10779)Full Changelog: https://github.com/remix-run/react-router/compare/react-router@6.15.0...react-router@6.16.0
Nothing published for this version
Nothing published for this version
Nothing published for this version
Add's a new redirectDocument() function which allows users to specify that a redirect from a loader/action should trigger a document reload (via windo
redirectDocument() function which allows users to specify that a redirect from a loader/action should trigger a document reload (via window.location) instead of attempting to navigate to the redirected location via React Router (#10705)useRevalidator is referentially stable across re-renders if revalidations are not actively occurring (#10707)URLSearchParams and the useSearchParams hook (#10620)unstable_usePrompt to avoid throwing an exception if the prompt is unblocked and a navigation is performed synchronously (#10687, #10718)useFormAction() for unspecified actions since it cannot be determined on the server and causes hydration issues (#10758)queryRoute that was not always identifying thrown Response instances (#10717)react-router-native: Update @ungap/url-search-params dependency from ^0.1.4 to ^0.2.2 (#10590)Full Changelog: https://github.com/remix-run/react-router/compare/react-router@6.14.2...react-router@6.15.0
Nothing published for this version
Add missing prop to populate history.state on submission navigations
<Form state> prop to populate history.state on submission navigations (#10630)defer promise resolves/rejects with undefined in order to match the behavior of loaders and actions which must return a value or null (#10690)<ScrollRestoration> (#10682)Route.lazy to prohibit returning an empty object (#10634)Error subclasses such as ReferenceError/TypeError (#10633)Full Changelog: https://github.com/remix-run/react-router/compare/react-router@6.14.1...react-router@6.14.2
@remix-run/router@1.7.2Nothing published for this version
Nothing published for this version
Fix loop in unstable_useBlocker when used with an unstable blocker function
unstable_useBlocker when used with an unstable blocker function (#10652)@remix-run/router@1.7.1Full Changelog: https://github.com/remix-run/react-router/compare/react-router@6.14.0...react-router@6.14.1
Date: 2023-06-30
unstable_useBlocker when used with an unstable blocker function (#10652)@remix-run/router@1.7.1Full Changelog: v6.14.0...v6.14.1
Nothing published for this version
Nothing published for this version
Please note that to avoid a breaking change, the default behavior will still encode a simple key/value JSON object into a FormData instance:
6.14.0 adds support for JSON and Text submissions via useSubmit/fetcher.submit since it's not always convenient to have to serialize into FormData if you're working in a client-side SPA. To opt-into these encodings you just need to specify the proper formEncType:
Opt-into application/json encoding:
function Component() {
let navigation = useNavigation();
let submit = useSubmit();
submit({ key: "value" }, { method: "post", encType: "application/json" });
// navigation.formEncType => "application/json"
// navigation.json => { key: "value" }
}
async function action({ request }) {
// request.headers.get("Content-Type") => "application/json"
// await request.json() => { key: "value" }
}
Opt-into text/plain encoding:
function Component() {
let navigation = useNavigation();
let submit = useSubmit();
submit("Text submission", { method: "post", encType: "text/plain" });
// navigation.formEncType => "text/plain"
// navigation.text => "Text submission"
}
async function action({ request }) {
// request.headers.get("Content-Type") => "text/plain"
// await request.text() => "Text submission"
}
⚠️ Default Behavior Will Change in v7
Please note that to avoid a breaking change, the default behavior will still encode a simple key/value JSON object into a FormData instance:
function Component() {
let navigation = useNavigation();
let submit = useSubmit();
submit({ key: "value" }, { method: "post" });
// navigation.formEncType => "application/x-www-form-urlencoded"
// navigation.formData => FormData instance
}
async function action({ request }) {
// request.headers.get("Content-Type") => "application/x-www-form-urlencoded"
// await request.formData() => FormData instance
}
This behavior will likely change in v7 so it's best to make any JSON object submissions explicit with formEncType: "application/x-www-form-urlencoded" or formEncType: "application/json" to ease your eventual v7 migration path.
application/json and text/plain encodings for useSubmit/fetcher.submit. To reflect these additional types, useNavigation/useFetcher now also contain navigation.json/navigation.text and fetcher.json/fetcher.text which include the json/text submission if applicable. (#10413)submitter element, prefer the built-in new FormData(form, submitter) instead of the previous manual approach in modern browsers (those that support the new submitter parameter) (#9865)
type="image" buttonsformdata-submitter-polyfillwindow.history.pushState/replaceState before updating React Router state (instead of after) so that window.location matches useLocation during synchronous React 17 rendering (#10448)
window.location and should always reference useLocation when possible, as window.location will not be in sync 100% of the time (due to popstate events, concurrent mode, etc.)shouldRevalidate for fetchers that have not yet completed a data load (#10623)basename from the location provided to <ScrollRestoration getKey> to match the useLocation behavior (#10550)basename from locations provided to unstable_useBlocker functions to match the useLocation behavior (#10573)unstable_useBlocker key issues in StrictMode (#10573)generatePath when passed a numeric 0 value parameter (#10612)tsc --skipLibCheck:false issues on React 17 (#10622)typescript to 5.1 (#10581)Full Changelog: https://github.com/remix-run/react-router/compare/react-router@6.13.0...react-router@6.14.0
basename from locations provided to unstable_useBlocker functions to match useLocation (#10573)generatePath when passed a numeric 0 value parameter (#10612)unstable_useBlocker key issues in StrictMode (#10573)tsc --skipLibCheck:false issues on React 17 (#10622)typescript to 5.1 (#10581)@remix-run/router@1.7.0Nothing published for this version
Nothing published for this version
6.13.0 is really a patch release in spirit but comes with a SemVer minor bump since we added a new future flag.
6.13.0 is really a patch release in spirit but comes with a SemVer minor bump since we added a new future flag.
The tl;dr; is that 6.13.0 is the same as 6.12.0 bue we've moved the usage of React.startTransition behind an opt-in future.v7_startTransition future flag because we found that there are applications in the wild that are currently using Suspense in ways that are incompatible with React.startTransition.
Therefore, in 6.13.0 the default behavior will no longer leverage React.startTransition:
<BrowserRouter>
<Routes>{/*...*/}</Routes>
</BrowserRouter>
<RouterProvider router={router} />
If you wish to enable React.startTransition, pass the future flag to your router component:
<BrowserRouter future={{ v7_startTransition: true }}>
<Routes>{/*...*/}</Routes>
</BrowserRouter>
<RouterProvider router={router} future={{ v7_startTransition: true }}/>
We recommend folks adopt this flag sooner rather than later to be better compatible with React concurrent mode, but if you run into issues you can continue without the use of React.startTransition until v7. Issues usually boil down to creating net-new promises during the render cycle, so if you run into issues when opting into React.startTransition, you should either lift your promise creation out of the render cycle or put it behind a useMemo.
React.startTransition usage behinds a future flag (#10596)React.startTransition minification bug in production mode (#10588)Full Changelog: https://github.com/remix-run/react-router/compare/react-router@6.12.1...react-router@6.13.0
Move React.startTransition usage behind a future flag to avoid issues with existing incompatible Suspense usages. We recommend folks adopting this flag to be better compatible with React concurrent mode, but if you run into issues you can continue without the use of startTransition until v7. Issues usually boils down to creating net-new promises during the render cycle, so if you run into issues you should either lift your promise creation out of the render cycle or put it behind a useMemo. (#10596)
Existing behavior will no longer include React.startTransition:
<BrowserRouter>
<Routes>{/*...*/}</Routes>
</BrowserRouter>
<RouterProvider router={router} />
If you wish to enable React.startTransition, pass the future flag to your component:
<BrowserRouter future={{ v7_startTransition: true }}>
<Routes>{/*...*/}</Routes>
</BrowserRouter>
<RouterProvider router={router} future={{ v7_startTransition: true }}/>
React.startTransition minification bug in production mode (#10588)Nothing published for this version
Nothing published for this version
> Please use version 6.13.0 or later instead of 6.12.0/6.12.1. These versions suffered from some Webpack build/minification issues resulting failed bu
Warning Please use version
6.13.0or later instead of6.12.0/6.12.1. These versions suffered from some Webpack build/minification issues resulting failed builds or invalid minified code in your production bundles. See #10569 and #10579 for more details.
React.startTransition to fix webpack + react 17 compilation error (#10569)Full Changelog: https://github.com/remix-run/react-router/compare/react-router@6.12.0...react-router@6.12.1
[!WARNING] Please use version
6.13.0or later instead of6.12.1. This version suffers from awebpack/terserminification issue resulting in invalid minified code in your resulting production bundles which can cause issues in your application. See #10579 for more details.
React.startTransition to fix webpack + react 17 compilation error (#10569)Date: 2023-06-08
[!WARNING] Please use version
6.13.0or later instead of6.12.0/6.12.1. These versions suffered from some Webpack build/minification issues resulting failed builds or invalid minified code in your production bundles. See #10569 and #10579 for more details.
React.startTransition to fix webpack + react 17 compilation error (#10569)Full Changelog: v6.12.0...v6.12.1
Nothing published for this version
> Please use version 6.13.0 or later instead of 6.12.0/6.12.1. These versions suffered from some Webpack build/minification issues resulting failed bu
Warning Please use version
6.13.0or later instead of6.12.0/6.12.1. These versions suffered from some Webpack build/minification issues resulting failed builds or invalid minified code in your production bundles. See #10569 and #10579 for more details.
With 6.12.0 we've added better support for suspending components by wrapping the internal router state updates in React.startTransition. This means that, for example, if one of your components in a destination route suspends and you have not provided a Suspense boundary to show a fallback, React will delay the rendering of the new UI and show the old UI until that asynchronous operation resolves. This could be useful for waiting for things such as waiting for images or CSS files to load (and technically, yes, you could use it for data loading but we'd still recommend using loaders for that 😀). For a quick overview of this usage, check out Ryan's demo on Twitter.
React.startTransition (#10438)DOMException (DataCloneError) when attempting to perform a PUSH navigation with non-serializable state. (#10427)jest and jsdom (#10453)@remix-run/router@1.6.3 (Changelog)Full Changelog: https://github.com/remix-run/react-router/compare/react-router@6.11.2...react-router@6.12.0
React.startTransition if it exists (#10438)@remix-run/router@1.6.3Nothing published for this version
Nothing published for this version
Fix basename duplication in descendant inside a
basename duplication in descendant <Routes> inside a <RouterProvider> (#10492)SetURLSearchParams type (#10444)manifest in _internalSetRoutes (#10437)Full Changelog: https://github.com/remix-run/react-router/compare/react-router@6.11.1...react-router@6.11.2
basename duplication in descendant <Routes> inside a <RouterProvider> (#10492)@remix-run/router@1.6.2Date: 2023-05-17
basename duplication in descendant <Routes> inside a <RouterProvider> (#10492)SetURLSearchParams type (#10444)manifest in _internalSetRoutes (#10437)Full Changelog: v6.11.1...v6.11.2
Nothing published for this version
Fix usage of Component API within descendant
Component API within descendant <Routes> (#10434)useNavigate from <Routes> inside a <RouterProvider> (#10432)<Navigate> in strict mode when using a data router (#10435)basename handling when navigating without a path (#10433)/path#hash -> /path#hash) (#10408)Full Changelog: https://github.com/remix-run/react-router/compare/react-router@6.11.0...react-router@6.11.1
Date: 2023-05-03
Component API within descendant <Routes> (#10434)useNavigate from <Routes> inside a <RouterProvider> (#10432)<Navigate> in strict mode when using a data router (#10435)basename handling when navigating without a path (#10433)/path#hash -> /path#hash) (#10408)Full Changelog: v6.11.0...v6.11.1
Nothing published for this version
Enable basename support in useFetcher
basename support in useFetcher (#10336)
basename then you will need to remove the manually prepended basename from your fetcher calls (fetcher.load('/basename/route') -> fetcher.load('/route'))@remix-run/router@1.6.0 (Changelog)RouterProvider, useNavigate/useSubmit/fetcher.submit are now stable across location changes, since we can handle relative routing via the @remix-run/router instance and get rid of our dependence on useLocation() (#10336)
BrowserRouter, these hooks remain unstable across location changes because they still rely on useLocation()action submissions or router.revalidate calls (#10344)Component instead of element on a route definition (#10287)<Link to="//"> and other invalid URL values (#10367)useSyncExternalStore to useState for internal @remix-run/router router state syncing in <RouterProvider>. We found some subtle bugs where router state updates got propagated before other normal useState updates, which could lead to foot guns in useEffect calls. (#10377, #10409)<Routes> when RouterProvider errors existed (#10374)useNavigate in the render cycle by setting the activeRef in a layout effect, allowing the navigate function to be passed to child components and called in a useEffect there (#10394)useRevalidator() to resolve a loader-driven error boundary scenario (#10369)LoaderFunction/ActionFunction return type to prevent undefined from being a valid return value (#10267)fetcher.load call to a route without a loader (#10345)AbortController usage between revalidating fetchers and the thing that triggered them such that the unmount/deletion of a revalidating fetcher doesn't impact the ongoing triggering navigation/revalidation (#10271)Full Changelog: https://github.com/remix-run/react-router/compare/react-router@6.10.0...react-router@6.11.0
<Routes> when RouterProvider errors existed (#10374)Component instead of element on a route definition (#10287)useNavigate in the render cycle by setting the activeRef in a layout effect, allowing the navigate function to be passed to child components and called in a useEffect there. (#10394)useSyncExternalStore to useState for internal @remix-run/router router state syncing in <RouterProvider>. We found some subtle bugs where router state updates got propagated before other normal useState updates, which could lead to footguns in useEffect calls. (#10377, #10409)useRevalidator() to resolve a loader-driven error boundary scenario (#10369)RouterProvider, useNavigate/useSubmit/fetcher.submit are now stable across location changes, since we can handle relative routing via the @remix-run/router instance and get rid of our dependence on useLocation(). When using BrowserRouter, these hooks remain unstable across location changes because they still rely on useLocation(). (#10336)@remix-run/router@1.6.0Nothing published for this version
Nothing published for this version
Nothing published for this version
We recently published a post over on the Remix Blog titled "Future Proofing Your Remix App" that goes through our strategy to ensure smooth upgrades f
We recently published a post over on the Remix Blog titled "Future Proofing Your Remix App" that goes through our strategy to ensure smooth upgrades for your Remix and React Router apps going forward. React Router 6.10.0 adds support for these flags (for data routers) which you can specify when you create your router:
const router = createBrowserRouter(routes, {
future: {
// specify future flags here
},
});
You can also check out the docs here and here.
The first future flag being introduced is future.v7_normalizeFormMethod which will normalize the exposed useNavigation()/useFetcher() formMethod fields as uppercase HTTP methods to align with the fetch() (and some Remix) behavior. (#10207)
future.v7_normalizeFormMethod is unspecified or set to false (default v6 behavior),
useNavigation().formMethod is lowercaseuseFetcher().formMethod is lowercasefuture.v7_normalizeFormMethod === true:
useNavigation().formMethod is UPPERCASEuseFetcher().formMethod is UPPERCASEcreateStaticHandler to also check for ErrorBoundary on routes in addition to errorElement (#10190)createRoutesFromElements (#10193)shouldRevalidate if the fetcher action redirects (#10208)lazy() errors during router initialization (#10201)instanceof check for DeferredData to be resilient to ESM/CJS boundaries in SSR bundling scenarios (#10247)@remix-run/web-fetch@4.3.3 (#10216)Full Changelog: https://github.com/remix-run/react-router/compare/react-router@6.9.0...react-router@6.10.0
future.v7_normalizeFormMethod which will normalize the exposed useNavigation()/useFetcher() formMethod fields as uppercase HTTP methods to align with the fetch() behavior. (#10207)
future.v7_normalizeFormMethod === false (default v6 behavior),
useNavigation().formMethod is lowercaseuseFetcher().formMethod is lowercasefuture.v7_normalizeFormMethod === true:
useNavigation().formMethod is uppercaseuseFetcher().formMethod is uppercasecreateRoutesFromElements (#10193)@remix-run/router@1.5.0Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →