UNPKG

164 kB Markdown View Raw
1# `react-router`
2
3## v8.5.1
4
5### Patch Changes
6
7- Fix `URIError: URI malformed` when an API-only (`ssr: "unstable_api-only"`) server or an `ssr: false` dev server receives a URL path with a malformed percent-encoding ([#15649](https://github.com/remix-run/react-router/pull/15649))
8- Bound server route manifest processing for paths with expensive route expansion ([#15703](https://github.com/remix-run/react-router/pull/15703))
9 - Fall back to initial route discovery during server rendering and RSC document/data requests
10 - Account for the number and depth of candidate branches when using regex matching
11- Encode commas within paths sent to the lazy route discovery manifest endpoint so routes with commas in their paths are discovered correctly ([#15640](https://github.com/remix-run/react-router/pull/15640))
12- Fix fetcher revalidation errors bubbling to the root error boundary instead of the nearest boundary above the route that owns the fetcher ([#15676](https://github.com/remix-run/react-router/pull/15676))
13- Avoid duplicate history entries when posting a `<Form>` to the current URL with an encoded `action` ([#15679](https://github.com/remix-run/react-router/pull/15679))
14 - Replace the current history entry when the `action` contains characters that get percent-encoded, such as spaces or non-ASCII characters
15- Fix an unhandled promise rejection when the browser skips a `viewTransition` navigation, for example in a hidden tab ([#15582](https://github.com/remix-run/react-router/pull/15582))
16- Bubble rejected `lazy.Component` imports on loader-less routes to the nearest error boundary ([#15658](https://github.com/remix-run/react-router/pull/15658))
17 - Render the error boundary instead of a blank page
18- Preserve pending fetcher mutation revalidation when an older navigation or background reload completes to prevent stale loader data ([#15686](https://github.com/remix-run/react-router/pull/15686))
19 - Keep newer fetcher loads cancellable and preserve them when earlier revalidations finish or abort, preventing older responses from overwriting fresh fetcher data
20- Retry rejected `lazy` route imports instead of caching failures permanently ([#15689](https://github.com/remix-run/react-router/pull/15689))
21- Revalidate loader data when a fetcher action redirect is not followed ([#15557](https://github.com/remix-run/react-router/pull/15557))
22 - Revalidate when an action redirect is ignored because a newer navigation started or the fetcher unmounted while the action was running
23 - Include shared parent loaders when another navigation completed while the action was running
24 - Continue to respect `shouldRevalidate`
25 - Return fetchers to `idle` when a revalidation completes a pending navigation started by another fetcher's redirect
26- Avoid adding an incompatible `document.startViewTransition()` overload to the global `Document` type ([#15680](https://github.com/remix-run/react-router/pull/15680))
27 - Allow transition results to be assigned to the DOM `ViewTransition` type
28- Fix duplicate headers when throwing a redirect from an RSC server function ([#15667](https://github.com/remix-run/react-router/pull/15667))
29- Skip `deleteData` in `destroySession` when the session has no ID ([#15639](https://github.com/remix-run/react-router/pull/15639))
30 - Avoid failures when destroying a session without a cookie on storage that rejects an empty key
31- Surface the host's 404 response when a SPA fallback route has no prerendered data ([#15646](https://github.com/remix-run/react-router/pull/15646))
32 - Request single-fetch `.data` files for hydrating routes with a server `loader` in an `ssr: false` app with a `prerender` config
33 - Avoid the internal "No result found for routeId" error for non-prerendered parameterized paths served via the SPA fallback
34- Improve turbo-stream decoding validation and object property handling ([18e1fbd](https://github.com/remix-run/react-router/commit/18e1fbd))
35
36### Unstable Changes
37
38⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_
39
40- Add an opt-in `<Await unstable_promise={promise}>` implementation based on React's `use()` API ([#15678](https://github.com/remix-run/react-router/pull/15678))
41 - Use `React.use` instead of React Router's internal promise tracking
42 - Accept promise-like values and retain `errorElement`, `useAsyncValue`, and `useAsyncError` support
43 - Handle only promise rejections with `errorElement` when using `unstable_promise`, allowing child render errors to bubble to the nearest React error boundary
44 - Track streamed promises during decoding so settled server content stays visible during hydration updates with either Await API or direct `React.use()`
45
46## v8.5.0
47
48### Minor Changes
49
50- Deprecate React Router's view transition APIs in favor of React's `<ViewTransition>` component, available in React 19.3 and later ([#15493](https://github.com/remix-run/react-router/pull/15493))
51 - Deprecate the `viewTransition` props/options, `useViewTransitionState`, and `NavLink`'s `isTransitioning` render prop and `transitioning` class
52 - Preserve existing behavior, including support for older React versions
53 - See the [migration guide](https://reactrouter.com/how-to/view-transitions) for a navigation example and compatibility considerations
54
55### Patch Changes
56
57- Fix `<Await>` failing to server render promises decoded from an RSC payload, which caused the Suspense boundary to switch to client rendering ([#15597](https://github.com/remix-run/react-router/pull/15597))
58- Declare `@types/react` and `@types/react-dom` as optional peer dependencies so the shipped type definitions resolve React types under strict (non-hoisted) node_modules layouts ([#15528](https://github.com/remix-run/react-router/pull/15528))
59- Fix the `unstable_useRouterState` documentation example to call the imported alias ([#15535](https://github.com/remix-run/react-router/pull/15535))
60- Render the `HydrateFallback` of a route discovered through `patchRoutesOnNavigation` during initial hydration ([#15537](https://github.com/remix-run/react-router/pull/15537))
61 - Routes discovered during initial hydration are now exposed in `state.matches` while their loaders run, so `<RouterProvider>` renders down to the discovered route's `HydrateFallback` instead of rendering nothing
62- Fix router state recovery when updates occur before `RouterProvider` subscribes, including when other subscribers are already attached, and report current client errors once without replaying server errors during hydration ([#15637](https://github.com/remix-run/react-router/pull/15637))
63- Fix `matchPath` not treating a static segment as optional when it contains characters outside `[\w-]` ([#15425](https://github.com/remix-run/react-router/pull/15425))
64- Fix an RSC server crash when a client aborts a document request while the HTML stream waits for the RSC payload ([#15612](https://github.com/remix-run/react-router/pull/15612))
65- Stop revalidating a fetcher after `fetcher.reset()`, so its cleared data no longer comes back on the next revalidation ([#15633](https://github.com/remix-run/react-router/pull/15633))
66
67### Unstable Changes
68
69⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_
70
71- Add an `unstable_fetch` prop to `<HydratedRouter>` to customize JavaScript-issued manifest and server data requests in conventional Framework Mode ([#15586](https://github.com/remix-run/react-router/pull/15586))
72 - The function receives the intended request as well as context identifying the type of request
73 - Data request context includes `navigationType` (`"PUSH"`, `"REPLACE"`, or `"POP"` for navigation-initiated requests, including reloaded fetchers; `null` otherwise)
74 - Data strategies receive equivalent metadata through `unstable_initiator` and `unstable_navigationType`
75 - The custom fetch context is a discriminated union, so narrowing `type` to `"navigation"` guarantees a non-null `navigationType`, while other data requests have a `null` `navigationType`
76 - Fetchers reloaded after an initialization redirect retain the `"initialization"` type and include their fetcher key
77 - Like other router initialization options, the implementation is captured when the singleton router is created and thus subsequent prop changes are ignored
78 - Browser-managed data prefetches from `<Link prefetch>` use native `<link rel="prefetch">` elements and do not call the custom implementation
79 - Use the callback for custom fetch options, custom headers, safe request retries, or response header inspection
80 - Return response bodies unchanged so React Router can decode its manifest and Turbo Stream data protocols
81- Support API-only Framework Mode with runtime server data loading, actions, revalidation, and lazy route discovery ([#15601](https://github.com/remix-run/react-router/pull/15601))
82 - Hydrate prerendered pages from build-time data and fetch server loader data when hydrating a SPA fallback
83 - Preserve normal loader revalidation and server-action support for eagerly loaded and lazily discovered routes, and honor loader opt-outs when making server data requests
84- Add `unstable_useRouteDiscovery` for application-controlled route discovery in conventional Framework Mode ([#15602](https://github.com/remix-run/react-router/pull/15602))
85 - Discover selected destinations or load the running client's full route manifest without loading route modules
86 - Compose manifest-mismatch handlers, with shared recovery and cancellation that preserves application state
87 - Keep full-manifest failures catchable without rendering error boundaries, whether mismatch handlers use the hook or event's `loadAllRoutes()`
88 - Cancel pending revalidation alongside a canceled navigation, retaining existing data and settling interrupted fetchers before restoring Back/Forward history
89 - Enable `future.unstable_customRouteDiscovery` to opt in
90 - Apps without the flag retain existing discovery behavior
91 - Call `event.defaultBehavior()` from a custom mismatch handler to explicitly run built-in recovery
92- Return middleware short-circuit responses as-is for document requests in RSC modes, including resource routes, instead of decoding non-RSC bodies as Flight ([#15628](https://github.com/remix-run/react-router/pull/15628))
93 - Include server middleware in both eager and lazy RSC route configuration types
94 - Preserve HTML rendering for cached Flight responses returned by middleware, and pass through raw responses that replace the result of `next()`
95
96## v8.4.0
97
98### Minor Changes
99
100- Deprecate the `createStaticRouter({ branches })` option ([#15297](https://github.com/remix-run/react-router/pull/15297))
101 - `createStaticRouter` now caches route branches internally, ignores `branches`, and logs a deprecation warning when the option is provided
102 - The deprecated `EntryContext.branches` property remains available for compatibility but is always an empty array
103
104### Patch Changes
105
106- Prevent stale route discovery during manifest version-mismatch recovery ([#15489](https://github.com/remix-run/react-router/pull/15489))
107 - Keep concurrent manifest responses pending while a document reload is in progress
108 - Report a discovery error when a previous reload failed to resolve a version mismatch instead of loading a stale route or reloading repeatedly
109 - Fail pending requests if a document reload does not complete within five seconds or the document is restored from the back-forward cache, allowing subsequent requests to recover
110- Preserve lazy route module import errors during SPA navigations instead of replacing them with a missing `dataStrategy` result error ([#15464](https://github.com/remix-run/react-router/pull/15464))
111- Switch to more granular internal router contexts to avoid unnecessary route component re-renders when unrelated data router state changes ([#15376](https://github.com/remix-run/react-router/pull/15376))
112 - ⚠️ This contains some breaking changes to exported `UNSAFE_` contexts, so please review carefully if you are using those unsafe exports
113- Correctly escape streamed RSC redirect locations in meta tag attributes ([#15491](https://github.com/remix-run/react-router/pull/15491))
114- Avoid unintended `document.startViewTransition` calls during initial hydration and `router.revalidate()` calls ([#15484](https://github.com/remix-run/react-router/pull/15484))
115- Fix `SingleFetchNoResultError` thrown when a fetcher revalidates against a splat route during lazy route discovery ([#15395](https://github.com/remix-run/react-router/pull/15395))
116 - Track discovery per fetcher load so revalidation waits for the current load's discovery, even when the fetcher key is reused, while still restarting interrupted loaders after discovery completes
117- Preserve the underlying decode failure as the `cause` of the `Unable to decode turbo-stream response` error ([#15450](https://github.com/remix-run/react-router/pull/15450))
118
119### Unstable Changes
120
121⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_
122
123- Add a Data Mode `future.unstable_routePatternMatching` flag for more efficient route matching powered by `@remix-run/route-pattern` ([#15298](https://github.com/remix-run/react-router/pull/15298))
124 - Add an `unstable_validateParams` route field to reject invalid parameter values and continue matching
125- Document access control requirements for RSC Server Functions ([#15490](https://github.com/remix-run/react-router/pull/15490))
126 - Treat every Server Function as a public endpoint that must perform all of its own access control checks
127 - Recommend route actions when access control should be provided by route middleware
128
129## v8.3.1
130
131### Patch Changes
132
133- Fix `Expected fetcher: <key>` error thrown on navigation when a fetcher is aborted during its post-action revalidation ([#15365](https://github.com/remix-run/react-router/pull/15365))
134- Fix lazy route discovery caching a path as discovered when the triggering navigation was aborted after the manifest response settled but before the route tree was patched, which permanently (for the session) shadowed the real route behind a catch-all or produced 404s on every subsequent visit ([#15399](https://github.com/remix-run/react-router/pull/15399))
135- Improve route matching performance for long paths ([#15417](https://github.com/remix-run/react-router/pull/15417))
136- Improve validation of action request origins ([#15419](https://github.com/remix-run/react-router/pull/15419))
137- Fix `<ScrollRestoration>` leaving `history.scrollRestoration` set to `"auto"` after a bfcache restore, which let the browser restore scroll on subsequent history traversals before the destination route had rendered ([#15397](https://github.com/remix-run/react-router/pull/15397))
138- Properly respect the `relative` option in `useSubmit`/`fetcher.submit` when resolivng the `action` path ([#15400](https://github.com/remix-run/react-router/pull/15400))
139- Add additional URL validation on client side navigations/redirects ([#15445](https://github.com/remix-run/react-router/pull/15445))
140
141## v8.3.0
142
143### Patch Changes
144
145- Encode path params in `href`/`generatePath` per RFC 3986 path-segment rules instead of `encodeURIComponent` ([#15310](https://github.com/remix-run/react-router/pull/15310))
146 - Characters that are valid literally in a path segment (`$ & + , ; = : @` — RFC 3986 `pchar`) are no longer percent-encoded, so values like a semver build `1.0.0+1` interpolate unchanged instead of becoming `1.0.0%2B1`
147 - Structural/unsafe characters (`/ ? # %`, whitespace, non-ASCII) are still escaped exactly as before
148- Use `crypto.randomUUID()` for `createMemorySessionStorage` session ids ([#15302](https://github.com/remix-run/react-router/pull/15302))
149 - `createMemorySessionStorage` is only intended for local development and testing - sessions are lost when the server restarts
150- Fix `NavLink` not applying its `pending` state when `to` has a trailing slash ([#15300](https://github.com/remix-run/react-router/pull/15300))
151- Preserve RSC route component metadata so routes with a `clientLoader` can skip unnecessary server requests once their components have rendered while still fetching missing server-rendered elements ([#15323](https://github.com/remix-run/react-router/pull/15323))
152- Harden RSC CSRF code paths ([#15311](https://github.com/remix-run/react-router/pull/15311))
153- Fix server crash (`TypeError: Invalid state: Unable to enqueue`) when a request is aborted while the RSC HTML stream has a pending flush ([#15286](https://github.com/remix-run/react-router/pull/15286))
154 - Handle cancellation of the `injectRSCPayload` readable side, clear the pending flush, and cancel the underlying RSC payload stream
155
156### Unstable Changes
157
158⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_
159
160- Detect stale RSC clients during lazy route discovery and reload the destination document ([#15318](https://github.com/remix-run/react-router/pull/15318))
161
162 #### Migration
163
164 Apps using the default RSC Framework entry do not need to make any changes. Apps with a custom `entry.rsc.tsx` should import the generated client version and pass it to `unstable_matchRSCServerRequest`:
165
166 ```tsx
167 import clientVersion from "virtual:react-router/unstable_rsc/client-version";
168
169 return unstable_matchRSCServerRequest({
170 // ...
171 clientVersion,
172 });
173 ```
174
175- Add CSP nonce support to RSC document rendering ([#15320](https://github.com/remix-run/react-router/pull/15320))
176 - Add `nonce` options to `unstable_routeRSCServerRequest` and `unstable_RSCStaticRouter`
177 - Forward the nonce to the HTML renderer and apply it to injected RSC payload scripts and nonce-aware framework components
178
179 To adopt nonce-based CSP, update your `entry.ssr.tsx` (run `react-router reveal entry.ssr` first in RSC Framework Mode) to generate a fresh nonce for each request. Pass it to `routeRSCServerRequest`, spread the `renderHTML` options into React's HTML renderer, pass `options.nonce` to `RSCStaticRouter`, and use the same nonce in the `Content-Security-Policy` response header:
180
181 ```tsx
182 const nonce = crypto.randomUUID();
183 const response = await routeRSCServerRequest({
184 request,
185 serverResponse,
186 createFromReadableStream,
187 nonce,
188 async renderHTML(getPayload, options) {
189 const payload = getPayload();
190 return renderHTMLToReadableStream(
191 <RSCStaticRouter getPayload={getPayload} nonce={options.nonce} />,
192 {
193 ...options,
194 bootstrapScriptContent,
195 formState: await payload.formState,
196 signal: request.signal,
197 },
198 );
199 },
200 });
201 response.headers.set(
202 "Content-Security-Policy",
203 `script-src 'self' 'nonce-${nonce}'`,
204 );
205 ```
206
207## v8.2.0
208
209### Patch Changes
210
211- Fix `href()` to properly stringify and URL-encode param values, matching `generatePath()` ([#15277](https://github.com/remix-run/react-router/pull/15277))
212 - splat params preserve path separators while encoding each segment individually
213- Fix dynamic param extraction for routes with optional static segments ([#15200](https://github.com/remix-run/react-router/pull/15200))
214 - When a route path contains optional static segments (e.g. `/school?/user/:id`), the internal regex's incorrectly shifted parameter indices resulting in incorrect parameter extraction
215 - Consecutive optional static segments (e.g. `/one?/two?`) were only partially handled
216- Preserve navigation blocker state through a revalidation ([#15246](https://github.com/remix-run/react-router/pull/15246))
217- Fix route ranking for dynamic parameters with static extension suffixes ([#15273](https://github.com/remix-run/react-router/pull/15273))
218 - These were not being detected as dynamic param segments and instead got incorrectly scored higher as a static segment
219 - This meant they could potentially tie truly static routes like `/sitemap.xml` and outrank them based on definition order
220 - These are now correctly identified as dynamic parameter segments and scored correctly
221- Use ReactFormState types instead of unknown ([#15263](https://github.com/remix-run/react-router/pull/15263))
222
223## v8.1.0
224
225### Minor Changes
226
227- Return route metadata from server request, client navigation, and client fetcher instrumentations ([#15235](https://github.com/remix-run/react-router/pull/15235))
228 - Adds result metadata after instrumented calls complete, including the URL, matched route pattern, and params
229 - Adds known HTTP status codes to server request handler instrumentation results
230
231## v8.0.1
232
233### Patch Changes
234
235- Remove the obsolete `AppLoadContext` type export accidentally left over from v7 now that middleware is always enabled and server request context is provided through `RouterContextProvider`. ([#15207](https://github.com/remix-run/react-router/pull/15207))
236
237## v8.0.0
238
239### Major Changes
240
241- Remove the `future.v8_trailingSlashAwareDataRequests` flag ([#15100](https://github.com/remix-run/react-router/pull/15100))
242 - Trailing slash-aware data request URLs are now the default behavior.
243- Update `tsconfig.json` `target`/`lib` from `ES2020 -> ES2022` ([591853e](https://github.com/remix-run/react-router/commit/591853e))
244- Switch the published packages in `packages/` to ESM-only. ([#14895](https://github.com/remix-run/react-router/pull/14895)) ([59ebcf1](https://github.com/remix-run/react-router/commit/59ebcf1))
245- Remove deprecated `data` parameter in favor of `loaderData` for `meta` APIs (to align with `Route.ComponentProps`) ([#14931](https://github.com/remix-run/react-router/pull/14931))
246 - `Route.MetaArgs`, `Route.MetaMatch`, `MetaArgs`, `MetaMatch`, `Route.ComponentProps.matches`, `UIMatch`
247- Remove `future.v8_passThroughRequests` flag - the raw incoming `request` is now always passed through to `loader`/`action`. Use `url` for the normalized URL without React Router-specific implementation details (`.data` suffixes, `index`/`_routes` search params). ([#15079](https://github.com/remix-run/react-router/pull/15079))
248- Remove internal `hasErrorBoundary` field added to `router.routes` when using a data router ([#15074](https://github.com/remix-run/react-router/pull/15074))
249 - This should not impact user-facing code since this was an internal prop and was computed based on the presence of `ErrorBoundary` or `errorElement` on your route
250 - `hasErrorBoundary` is no longer accepted on `RouteObject` (`IndexRouteObject`/`NonIndexRouteObject`), `DataRouteObject`, `<Route>` JSX props, or as a key in `lazy` route definitions.
251 - The `MapRoutePropertiesFunction` signature no longer requires returning `hasErrorBoundary`; the router infers it directly.
252- Remove `react-router-dom` package ([#15076](https://github.com/remix-run/react-router/pull/15076))
253 - In v7 everything DOM-specific was collapsed into `react-router/dom`
254 - `react-router-dom` was kept around as a convenience so existing v6 app imports would still work
255 - For v8, you will need to swap `react-router-dom` imports:
256 - `RouterProvider`/`HydratedRouter` should be imported from `react-router/dom`
257 - Everything else should be imported from `react-router`
258- Remove `future.v8_middleware` flag — middleware is always enabled in v8 ([#15078](https://github.com/remix-run/react-router/pull/15078))
259 - The `future.v8_middleware` flag has been removed; middleware is now always enabled
260 - The `context` parameter passed to `loader`, `action`, and `middleware` functions is always a `RouterContextProvider` instance
261 - `getLoadContext` functions in custom servers must return a `RouterContextProvider` — returning a plain object is no longer supported
262 - The `MiddlewareEnabled` type (previously exported as `UNSAFE_MiddlewareEnabled`) has been removed since the conditional it gated is now unconditional
263 - The `Future` module augmentation pattern (`interface Future { v8_middleware: true }`) is no longer needed to type `context` in Data Mode
264- Update minimum Node version to 22.22.0 ([#14928](https://github.com/remix-run/react-router/pull/14928))
265- Update minimum React version to 19.2.7 ([#15062](https://github.com/remix-run/react-router/pull/15062))
266
267### Minor Changes
268
269- Bump dependencies ([#15080](https://github.com/remix-run/react-router/pull/15080))
270 - Bumped `cookie` from `^1.0.1` to `^1.1.1`
271 - Bumped `set-cookie-parser` from `^2.6.0` to `^3.1.0`
272
273### Patch Changes
274
275- Ensure client middleware errors load lazy route error boundaries before bubbling ([#15086](https://github.com/remix-run/react-router/pull/15086))
276- Remove explicit `onSubmit` type override from `SharedFormProps` to fix deprecation warning with `@types/react@19.x` ([#14932](https://github.com/remix-run/react-router/pull/14932)) ([59ebcf1](https://github.com/remix-run/react-router/commit/59ebcf1))
277- Update package builds to preserve individual module files in published artifacts. Public APIs and documented import paths are unchanged. ([#15092](https://github.com/remix-run/react-router/pull/15092))
278 - Updated package TypeScript configs to support modern module syntax used by the build configuration.
279- Migrate package builds from `tsup` to `tsdown`. Published package entry points and public APIs are unchanged. ([#15092](https://github.com/remix-run/react-router/pull/15092))
280- Upgrade React Router's TypeScript tooling to TypeScript 6. Runtime behavior and public APIs are unchanged. ([#15092](https://github.com/remix-run/react-router/pull/15092))
281
282## v7.18.0
283
284### Patch Changes
285
286- Fix server handler prerender responses when using `ssr: false` and `future.v8_trailingSlashAwareDataRequests: true`. Avoids false positive "SPA Mode" detection when serving prerendered paths ([#15173](https://github.com/remix-run/react-router/pull/15173))
287- Use the `ServerRouter` nonce for nonce-aware SSR components when they don't provide their own value so strict CSP pages can load them. ([#15170](https://github.com/remix-run/react-router/pull/15170))
288- Use `turbo-stream` to serialize and deserialize Framework Mode hydration errors ([#15175](https://github.com/remix-run/react-router/pull/15175))
289- Precompute route branch matchers to avoid recompiling route path regexes during matching ([#15186](https://github.com/remix-run/react-router/pull/15186))
290- Use the constructed request URL host when validating action request origins. ([#15185](https://github.com/remix-run/react-router/pull/15185))
291- Remove the un-documented custom error serialization logic from Data Mode SSR built-in hydration flows ([#15175](https://github.com/remix-run/react-router/pull/15175))
292- Validate protocols in RSC render redirects ([#15177](https://github.com/remix-run/react-router/pull/15177))
293- Consolidate url normalization logic and better handle mixed slashes ([#15176](https://github.com/remix-run/react-router/pull/15176))
294
295## v7.17.0
296
297### Minor Changes
298
299- Ship a subset of the official documentation inside the `react-router` package ([#15121](https://github.com/remix-run/react-router/pull/15121))
300 - Markdown docs are now available in `node_modules/react-router/docs`, letting AI coding agents and the React Router agent skills read official docs locally
301 - Excludes auto-generated API docs (`api/`), `community/` content, and tutorials (`tutorials/`)
302
303## v7.16.0
304
305### Minor Changes
306
307- Stabilize `future.unstable_trailingSlashAwareDataRequests` as `future.v8_trailingSlashAwareDataRequests` ([#15098](https://github.com/remix-run/react-router/pull/15098))
308
309### Patch Changes
310
311- Disable manifest path when lazy route dicovery is disabled ([#15068](https://github.com/remix-run/react-router/pull/15068))
312
313- Fix browser URL creation to use the configured history window instead of the global window. ([#15066](https://github.com/remix-run/react-router/pull/15066))
314 - Pass the history/router window through to `createBrowserURLImpl` so custom window contexts keep the correct URL origin.
315
316- Fix `useNavigation()` return type to preserve discriminated union across navigation states ([#15095](https://github.com/remix-run/react-router/pull/15095))
317
318- Widen `MetaDescriptor` `script:ld+json` type from `LdJsonObject` to `LdJsonObject | LdJsonObject[]` to permit multiple JSON-LD schemas in a single `<script type="application/ld+json">` tag emitted by `<Meta />` ([#15082](https://github.com/remix-run/react-router/pull/15082))
319
320## v7.15.1
321
322### Patch Changes
323
324- Update router to operate on fetcher Maps in an immutable manner to avoid delayed React renders from potentially reading an updated but not yet committed Map. This could result in brief flickers in some fetcher-driven optimistic UI scenarios. ([#15028](https://github.com/remix-run/react-router/pull/15028))
325- Fix `serverLoader()` returning stale SSR data when a client navigation aborts pending hydration before the hydration `clientLoader` resolves ([#15022](https://github.com/remix-run/react-router/pull/15022))
326- Fix `RouterProvider` `onError` callback not being called for synchronous initial loader errors in SPA mode ([#15039](https://github.com/remix-run/react-router/pull/15039)) ([#14942](https://github.com/remix-run/react-router/pull/14942))
327- Memoize `useFetchers` to return a stable identity and only change if fetchers changed ([#15028](https://github.com/remix-run/react-router/pull/15028))
328- Internal refactor to consolidate mutation request detection through shared utility ([#15033](https://github.com/remix-run/react-router/pull/15033))
329
330### Unstable Changes
331
332⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_
333
334- Add a new `unstable_useRouterState()` hook that consolidates access to active and pending router states (RFC: #12358) ([#15017](https://github.com/remix-run/react-router/pull/15017))
335 - Data/Framework/RSC only — throws when used without a data router
336 - This should allow you to consolidate usages of the following hooks which will likely be deprecated and removed in a future major version
337 - `useLocation`
338 - `useSearchParams`
339 - `useParams`
340 - `useMatches`
341 - `useNavigationType`
342 - `useNavigation`
343
344 ```ts
345 let { active, pending } = unstable_useRouterState();
346
347 // Active is always populated with the current location
348 active.location; // replaces `useLocation()`
349 active.searchParams; // replaces `useSearchParams()[0]`
350 active.params; // replaces `useParams()`
351 active.matches; // replaces `useMatches()`
352 active.type; // replaces `useNavigationType()`
353
354 // Pending is only populated during a navigation
355 pending.location; // replaces `useNavigation().location`
356 pending.searchParams; // equivalent to `new URLSearchParams(useNavigation().search)`
357 pending.params; // Not directly accessible today
358 pending.matches; // Not directly accessible today
359 pending.type; // Not directly accessible today
360 pending.state; // replaces `useNavigation().state`
361 pending.formMethod; // replaces useNavigation().formMethod
362 pending.formAction; // replaces useNavigation().formAction
363 pending.formEncType; // replaces useNavigation().formEncType
364 pending.formData; // replaces useNavigation().formData
365 pending.json; // replaces useNavigation().json
366 pending.text; // replaces useNavigation().text
367 ```
368
369## v7.15.0
370
371### Minor Changes
372
373- Stabilize `unstable_defaultShouldRevalidate` as `defaultShouldRevalidate` on `<Link>`, `<Form>`, `useLinkClickHandler`, `useSubmit`, `fetcher.submit`, and `setSearchParams` ([a993f09](https://github.com/remix-run/react-router/commit/a993f09))
374 - ⚠️ This is a breaking change if you have already opted into the unstable version - you will need to update your code accordingly
375
376- Stabilize the instrumentation APIs. `unstable_instrumentations` is now `instrumentations` and `unstable_pattern` is now `pattern` ([a993f09](https://github.com/remix-run/react-router/commit/a993f09))
377 - The `unstable_ServerInstrumentation`, `unstable_ClientInstrumentation`, `unstable_InstrumentRequestHandlerFunction`, `unstable_InstrumentRouterFunction`, `unstable_InstrumentRouteFunction`, and `unstable_InstrumentationHandlerResult` types have had their `unstable_` prefixes removed
378 - ⚠️ This is a breaking change if you have already opted into the unstable version - you will need to update your code accordingly
379
380- Stabilize `unstable_mask` as `mask` on `<Link>`, `useLinkClickHandler`, and `useNavigate`, and rename the corresponding `Location.unstable_mask` field to `Location.mask` ([a993f09](https://github.com/remix-run/react-router/commit/a993f09))
381 - ⚠️ This is a breaking change if you have already opted into the unstable version - you will need to update your code accordingly
382
383- Stabilize the `unstable_normalizePath` option on `staticHandler.query` and `staticHandler.queryRoute` as `normalizePath` ([a993f09](https://github.com/remix-run/react-router/commit/a993f09))
384 - ⚠️ This is a breaking change if you have already opted into the unstable version - you will need to update your code accordingly
385
386- Stabilize `future.unstable_passThroughRequests` as `future.v8_passThroughRequests` ([a993f09](https://github.com/remix-run/react-router/commit/a993f09))
387 - ⚠️ This is a breaking change if you have already opted into the unstable version - you will need to update your code accordingly
388
389- Remove `unstable_subResourceIntegrity` from the runtime `FutureConfig` type; the flag is now controlled by the top-level `subResourceIntegrity` option in `react-router.config.ts` ([a993f09](https://github.com/remix-run/react-router/commit/a993f09))
390 - ⚠️ This is a breaking change if you have already opted into the unstable version - you will need to update your code accordingly
391
392- Stabilize `unstable_url` as `url` on `loader`, `action`, and `middleware` function args ([a993f09](https://github.com/remix-run/react-router/commit/a993f09))
393 - ⚠️ This is a breaking change if you have already opted into the unstable version - you will need to update your code accordingly
394
395- Stabilize `unstable_useTransitions` as `useTransitions` on `<BrowserRouter>`, `<HashRouter>`, `<HistoryRouter>`, `<MemoryRouter>`, `<Router>`, `<RouterProvider>`, `<HydratedRouter>`, and `useLinkClickHandler` ([a993f09](https://github.com/remix-run/react-router/commit/a993f09))
396 - ⚠️ This is a breaking change if you have already opted into the unstable version - you will need to update your code accordingly
397
398### Patch Changes
399
400- Add `nonce` to `<Scripts>` `<link rel="modulepreload">` elements (if provided) ([af5d49b](https://github.com/remix-run/react-router/commit/af5d49b))
401
402- Fix a bug with `unstable_defaultShouldRevalidate={false}` where parent routes that did not export a `shouldRevalidate` function could be incorrectly included in the single fetch call for new child route data ([#15012](https://github.com/remix-run/react-router/pull/15012))
403
404- Improve server-side route matching performance by pre-computing flattened/cached route branches ([#14967](https://github.com/remix-run/react-router/pull/14967)) ([af5d49b](https://github.com/remix-run/react-router/commit/af5d49b))
405 - Performance benchmarks showed roughly a 10-15% improvement in server-side request handling performance
406
407- Mark `mask` as an optional field in `Location` for easier mocking in unit tests ([#14999](https://github.com/remix-run/react-router/pull/14999))
408
409- Cache flattened/ranked route branches to optimize server-side route matching ([#14967](https://github.com/remix-run/react-router/pull/14967))
410
411- Improve route matching performance in Framework/Data Mode ([#14971](https://github.com/remix-run/react-router/pull/14971)) ([af5d49b](https://github.com/remix-run/react-router/commit/af5d49b))
412 - Avoiding unnecessary calls to `matchRoutes` in data router scenarios
413 - This includes adding back the optimization that was removed in `7.6.0` ([#13562](https://github.com/remix-run/react-router/pull/13562))
414 - The issues that prompted the revert have been addressed by using the available router `matches` but always updating `match.route` to the latest route in the `manifest`
415 - Leverage pre-computed pre-computing flattened/cached route branches during client side route matching
416 - Performance benchmarks showed roughly a 15-30% improvement in server-side request handling performance
417
418## v7.14.2
419
420### Patch Changes
421
422- Remove the un-documented custom error serialization logic from the internal turbo-stream implementation. React Router only automatically handles serialization of `Error` and it's standard subtypes (`SyntaxError`, `TypeError`, etc.). ([[aabf4a1](https://github.com/remix-run/react-router/commit/aabf4a1))
423
424- Properly handle parent middleware redirects during `fetcher.load` ([[aabf4a1](https://github.com/remix-run/react-router/commit/aabf4a1))
425
426- Remove redundant `Omit<RouterProviderProps, "flushSync">` from `react-router/dom` `RouterProvider` ([[aabf4a1](https://github.com/remix-run/react-router/commit/aabf4a1))
427
428- Improved types for `generatePath`'s `param` arg ([[aabf4a1](https://github.com/remix-run/react-router/commit/aabf4a1))
429
430 Type errors when required params are omitted:
431
432 ```ts
433 // Before
434 // Passes type checks, but throws at runtime 💥
435 generatePath(":required", { required: null });
436
437 // After
438 generatePath(":required", { required: null });
439 // ^^^^^^^^ Type 'null' is not assignable to type 'string'.ts(2322)
440 ```
441
442 Allow omission of optional params:
443
444 ```ts
445 // Before
446 generatePath(":optional?", {});
447 // ^^ Property 'optional' is missing in type '{}' but required in type '{ optional: string | null | undefined; }'.ts(2741)
448
449 // After
450 generatePath(":optional?", {});
451 ```
452
453 Allows extra keys:
454
455 ```ts
456 // Before
457 generatePath(":a", { a: "1", b: "2" });
458 // ^ Object literal may only specify known properties, and 'b' does not exist in type '{ a: string; }'.ts(2353)
459
460 // After
461 generatePath(":a", { a: "1", b: "2" });
462 ```
463
464## v7.14.1
465
466### Patch Changes
467
468- Fix a potential race condition that can occur when rendering a `HydrateFallback` and initial loaders land before the `router.subscribe` call happens in the `RouterProvider` layout effect
469- Normalize double-slashes in redirect paths
470
471## 7.14.0
472
473### Patch Changes
474
475- UNSTABLE RSC FRAMEWORK MODE BREAKING CHANGE - Existing route module exports remain unchanged from stable v7 non-RSC mode, but new exports are added for RSC mode. If you want to use RSC features, you will need to update your route modules to export the new annotations. ([#14901](https://github.com/remix-run/react-router/pull/14901))
476
477 If you are using RSC framework mode currently, you will need to update your route modules to the new conventions. The following route module components have their own mutually exclusive server component counterparts:
478
479 | Server Component Export | Client Component |
480 | ----------------------- | ----------------- |
481 | `ServerComponent` | `default` |
482 | `ServerErrorBoundary` | `ErrorBoundary` |
483 | `ServerLayout` | `Layout` |
484 | `ServerHydrateFallback` | `HydrateFallback` |
485
486 If you were previously exporting a `ServerComponent`, your `ErrorBoundary`, `Layout`, and `HydrateFallback` were also server components. If you want to keep those as server components, you can rename them and prefix them with `Server`. If you were previously importing the implementations of those components from a client module, you can simply inline them.
487
488 Example:
489
490 Before
491
492 ```tsx
493 import { ErrorBoundary as ClientErrorBoundary } from "./client";
494
495 export function ServerComponent() {
496 // ...
497 }
498
499 export function ErrorBoundary() {
500 return <ClientErrorBoundary />;
501 }
502
503 export function Layout() {
504 // ...
505 }
506
507 export function HydrateFallback() {
508 // ...
509 }
510 ```
511
512 After
513
514 ```tsx
515 export function ServerComponent() {
516 // ...
517 }
518
519 export function ErrorBoundary() {
520 // previous implementation of ClientErrorBoundary, this is now a client component
521 }
522
523 export function ServerLayout() {
524 // rename previous Layout export to ServerLayout to make it a server component
525 }
526
527 export function ServerHydrateFallback() {
528 // rename previous HydrateFallback export to ServerHydrateFallback to make it a server component
529 }
530 ```
531
532- rsc Link prefetch ([#14902](https://github.com/remix-run/react-router/pull/14902))
533
534- Remove recursion from turbo-stream v2 allowing for encoding / decoding of massive payloads. ([#14838](https://github.com/remix-run/react-router/pull/14838))
535
536- encodeViaTurboStream leaked memory via unremoved AbortSignal listener ([#14900](https://github.com/remix-run/react-router/pull/14900))
537
538## 7.13.2
539
540### Patch Changes
541
542- Fix clientLoader.hydrate when an ancestor route is also hydrating a clientLoader ([#14835](https://github.com/remix-run/react-router/pull/14835))
543
544- Fix type error when passing Framework Mode route components using `Route.ComponentProps` to `createRoutesStub` ([#14892](https://github.com/remix-run/react-router/pull/14892))
545
546- Fix percent encoding in relative path navigation ([#14786](https://github.com/remix-run/react-router/pull/14786))
547
548- Add `future.unstable_passThroughRequests` flag ([#14775](https://github.com/remix-run/react-router/pull/14775))
549
550 By default, React Router normalizes the `request.url` passed to your `loader`, `action`, and `middleware` functions by removing React Router's internal implementation details (`.data` suffixes, `index` + `_routes` query params).
551
552 Enabling this flag removes that normalization and passes the raw HTTP `request` instance to your handlers. This provides a few benefits:
553 - Reduces server-side overhead by eliminating multiple `new Request()` calls on the critical path
554 - Allows you to distinguish document from data requests in your handlers base don the presence of a `.data` suffix (useful for observability purposes)
555
556 If you were previously relying on the normalization of `request.url`, you can switch to use the new sibling `unstable_url` parameter which contains a `URL` instance representing the normalized location:
557
558 ```tsx
559 // ❌ Before: you could assume there was no `.data` suffix in `request.url`
560 export async function loader({ request }: Route.LoaderArgs) {
561 let url = new URL(request.url);
562 if (url.pathname === "/path") {
563 // This check will fail with the flag enabled because the `.data` suffix will
564 // exist on data requests
565 }
566 }
567
568 // ✅ After: use `unstable_url` for normalized routing logic and `request.url`
569 // for raw routing logic
570 export async function loader({ request, unstable_url }: Route.LoaderArgs) {
571 if (unstable_url.pathname === "/path") {
572 // This will always have the `.data` suffix stripped
573 }
574
575 // And now you can distinguish between document versus data requests
576 let isDataRequest = new URL(request.url).pathname.endsWith(".data");
577 }
578 ```
579
580- Internal refactor to consolidate framework-agnostic/React-specific route type layers - no public API changes ([#14765](https://github.com/remix-run/react-router/pull/14765))
581
582- Sync protocol validation to rsc flows ([#14882](https://github.com/remix-run/react-router/pull/14882))
583
584- Add a new `unstable_url: URL` parameter to route handler methods (`loader`, `action`, `middleware`, etc.) representing the normalized URL the application is navigating to or fetching, with React Router implementation details removed (`.data`suffix, `index`/`_routes` query params) ([#14775](https://github.com/remix-run/react-router/pull/14775))
585
586 This is being added alongside the new `future.unstable_passthroughRequests` future flag so that users still have a way to access the normalized URL when that flag is enabled and non-normalized `request`'s are being passed to your handlers. When adopting this flag, you will only need to start leveraging this new parameter if you are relying on the normalization of `request.url` in your application code.
587
588 If you don't have the flag enabled, then `unstable_url` will match `request.url`.
589
590## 7.13.1
591
592### Patch Changes
593
594- fix null reference exception in bad codepath leading to invalid route tree comparisons ([#14780](https://github.com/remix-run/react-router/pull/14780))
595
596- fix: clear timeout when turbo-stream encoding completes ([#14810](https://github.com/remix-run/react-router/pull/14810))
597
598- Improve error message when Origin header is invalid ([#14743](https://github.com/remix-run/react-router/pull/14743))
599
600- Fix matchPath optional params matching without a "/" separator. ([#14689](https://github.com/remix-run/react-router/pull/14689))
601 - matchPath("/users/:id?", "/usersblah") now returns null.
602 - matchPath("/test_route/:part?", "/test_route_more") now returns null.
603
604- add RSC unstable_getRequest ([#14758](https://github.com/remix-run/react-router/pull/14758))
605
606- Fix `HydrateFallback` rendering during initial lazy route discovery with matching splat route ([#14740](https://github.com/remix-run/react-router/pull/14740))
607
608- \[UNSTABLE] Add support for `<Link unstable_mask>` in Data Mode which allows users to navigate to a URL in the router but "mask" the URL displayed in the browser. This is useful for contextual routing usages such as displaying an image in a model on top of a gallery, but displaying a browser URL directly to the image that can be shared and loaded without the contextual gallery in the background. ([#14716](https://github.com/remix-run/react-router/pull/14716))
609
610 ```tsx
611 // routes/gallery.tsx
612 export function clientLoader({ request }: Route.LoaderArgs) {
613 let sp = new URL(request.url).searchParams;
614 return {
615 images: getImages(),
616 // When the router location has the image param, load the modal data
617 modalImage: sp.has("image") ? getImage(sp.get("image")!) : null,
618 };
619 }
620
621 export default function Gallery({ loaderData }: Route.ComponentProps) {
622 return (
623 <>
624 <GalleryGrid>
625 {loaderData.images.map((image) => (
626 <Link
627 key={image.id}
628 {/* Navigate the router to /galley?image=N */}}
629 to={`/gallery?image=${image.id}`}
630 {/* But display /images/N in the URL bar */}}
631 unstable_mask={`/images/${image.id}`}
632 >
633 <img src={image.url} alt={image.alt} />
634 </Link>
635 ))}
636 </GalleryGrid>
637
638 {/* When the modal data exists, display the modal */}
639 {data.modalImage ? (
640 <dialog open>
641 <img src={data.modalImage.url} alt={data.modalImage.alt} />
642 </dialog>
643 ) : null}
644 </>
645 );
646 }
647 ```
648
649 Notes:
650 - The masked location, if present, will be available on `useLocation().unstable_mask` so you can detect whether you are currently masked or not.
651 - Masked URLs only work for SPA use cases, and will be removed from `history.state` during SSR.
652 - This provides a first-class API to mask URLs in Data Mode to achieve the same behavior you could do in Declarative Mode via [manual `backgroundLocation` management](https://github.com/remix-run/react-router/tree/main/examples/modal).
653
654- RSC: Update failed origin checks to return a 400 status and appropriate UI instead of a generic 500 ([#14755](https://github.com/remix-run/react-router/pull/14755))
655
656- Preserve query parameters and hash on manifest version mismatch reload ([#14813](https://github.com/remix-run/react-router/pull/14813))
657
658## 7.13.0
659
660### Minor Changes
661
662- Add `crossOrigin` prop to `Links` component ([#14687](https://github.com/remix-run/react-router/pull/14687))
663
664### Patch Changes
665
666- Fix double slash normalization for useNavigate colon urls ([#14718](https://github.com/remix-run/react-router/pull/14718))
667- Update failed origin checks to return a 400 status instead of a 500 ([#14737](https://github.com/remix-run/react-router/pull/14737))
668- Bugfix #14666: Inline criticalCss is missing nonce ([#14691](https://github.com/remix-run/react-router/pull/14691))
669- Loosen `allowedActionOrigins` glob check so `**` matches all domains ([#14722](https://github.com/remix-run/react-router/pull/14722))
670
671## 7.12.0
672
673### Minor Changes
674
675- Add additional layer of CSRF protection by rejecting submissions to UI routes from external origins. If you need to permit access to specific external origins, you can specify them in the `react-router.config.ts` config `allowedActionOrigins` field. ([#14708](https://github.com/remix-run/react-router/pull/14708))
676
677### Patch Changes
678
679- Fix `generatePath` when used with suffixed params (i.e., "/books/:id.json") ([#14269](https://github.com/remix-run/react-router/pull/14269))
680
681- Export `UNSAFE_createMemoryHistory` and `UNSAFE_createHashHistory` alongside `UNSAFE_createBrowserHistory` for consistency. These are not intended to be used for new apps but intended to help apps usiong `unstable_HistoryRouter` migrate from v6->v7 so they can adopt the newer APIs. ([#14663](https://github.com/remix-run/react-router/pull/14663))
682
683- Escape HTML in scroll restoration keys ([#14705](https://github.com/remix-run/react-router/pull/14705))
684
685- Validate redirect locations ([#14706](https://github.com/remix-run/react-router/pull/14706))
686
687- \[UNSTABLE] Pass `<Scripts nonce>` value through to the underlying `importmap` `script` tag when using `future.unstable_subResourceIntegrity` ([#14675](https://github.com/remix-run/react-router/pull/14675))
688
689- \[UNSTABLE] Add a new `future.unstable_trailingSlashAwareDataRequests` flag to provide consistent behavior of `request.pathname` inside `middleware`, `loader`, and `action` functions on document and data requests when a trailing slash is present in the browser URL. ([#14644](https://github.com/remix-run/react-router/pull/14644))
690
691 Currently, your HTTP and `request` pathnames would be as follows for `/a/b/c` and `/a/b/c/`
692
693 | URL `/a/b/c` | **HTTP pathname** | **`request` pathname\`** |
694 | ------------ | ----------------- | ------------------------ |
695 | **Document** | `/a/b/c` | `/a/b/c` ✅ |
696 | **Data** | `/a/b/c.data` | `/a/b/c` ✅ |
697
698 | URL `/a/b/c/` | **HTTP pathname** | **`request` pathname\`** |
699 | ------------- | ----------------- | ------------------------ |
700 | **Document** | `/a/b/c/` | `/a/b/c/` ✅ |
701 | **Data** | `/a/b/c.data` | `/a/b/c` ⚠️ |
702
703 With this flag enabled, these pathnames will be made consistent though a new `_.data` format for client-side `.data` requests:
704
705 | URL `/a/b/c` | **HTTP pathname** | **`request` pathname\`** |
706 | ------------ | ----------------- | ------------------------ |
707 | **Document** | `/a/b/c` | `/a/b/c` ✅ |
708 | **Data** | `/a/b/c.data` | `/a/b/c` ✅ |
709
710 | URL `/a/b/c/` | **HTTP pathname** | **`request` pathname\`** |
711 | ------------- | ------------------ | ------------------------ |
712 | **Document** | `/a/b/c/` | `/a/b/c/` ✅ |
713 | **Data** | `/a/b/c/_.data` ⬅️ | `/a/b/c/` ✅ |
714
715 This a bug fix but we are putting it behind an opt-in flag because it has the potential to be a "breaking bug fix" if you are relying on the URL format for any other application or caching logic.
716
717 Enabling this flag also changes the format of client side `.data` requests from `/_root.data` to `/_.data` when navigating to `/` to align with the new format. This does not impact the `request` pathname which is still `/` in all cases.
718
719- Preserve `clientLoader.hydrate=true` when using `<HydratedRouter unstable_instrumentations>` ([#14674](https://github.com/remix-run/react-router/pull/14674))
720
721## 7.11.0
722
723### Minor Changes
724
725- Stabilize `<HydratedRouter onError>`/`<RouterProvider onError>` ([#14546](https://github.com/remix-run/react-router/pull/14546))
726
727### Patch Changes
728
729- add support for throwing redirect Response's at RSC render time ([#14596](https://github.com/remix-run/react-router/pull/14596))
730
731- Support for throwing `data()` and Response from server component render phase. Response body is not serialized as async work is not allowed as error encoding phase. If you wish to transmit data to the boundary, throw `data()` instead. ([#14632](https://github.com/remix-run/react-router/pull/14632))
732
733- Fix `unstable_useTransitions` prop on `<Router>` component to permit omission for backewards compatibility ([#14646](https://github.com/remix-run/react-router/pull/14646))
734
735- `routeRSCServerRequest` replace `fetchServer` with `serverResponse` ([#14597](https://github.com/remix-run/react-router/pull/14597))
736
737- \[UNSTABLE] Add a new `unstable_defaultShouldRevalidate` flag to various APIs to allow opt-ing out of standard revalidation behaviors. ([#14542](https://github.com/remix-run/react-router/pull/14542))
738
739 If active routes include a `shouldRevalidate` function, then your value will be passed as `defaultShouldRevalidate` in those function so that the route always has the final revalidation determination.
740 - `<Form method="post" unstable_defaultShouldRevalidate={false}>`
741 - `submit(data, { method: "post", unstable_defaultShouldRevalidate: false })`
742 - `<fetcher.Form method="post" unstable_defaultShouldRevalidate={false}>`
743 - `fetcher.submit(data, { method: "post", unstable_defaultShouldRevalidate: false })`
744
745 This is also available on non-submission APIs that may trigger revalidations due to changing search params:
746 - `<Link to="/" unstable_defaultShouldRevalidate={false}>`
747 - `navigate("/?foo=bar", { unstable_defaultShouldRevalidate: false })`
748 - `setSearchParams(params, { unstable_defaultShouldRevalidate: false })`
749
750- Allow redirects to be returned from client side middleware ([#14598](https://github.com/remix-run/react-router/pull/14598))
751
752- Handle `dataStrategy` implementations that return insufficient result sets by adding errors for routes without any available result ([#14627](https://github.com/remix-run/react-router/pull/14627))
753
754## 7.10.1
755
756### Patch Changes
757
758- Update the `useOptimistic` stub we provide for React 18 users to use a stable setter function to avoid potential `useEffect` loops - specifically when using `<Link viewTransition>` ([#14628](https://github.com/remix-run/react-router/pull/14628))
759
760## 7.10.0
761
762### Minor Changes
763
764- Stabilize `fetcher.reset()` ([#14545](https://github.com/remix-run/react-router/pull/14545))
765 - ⚠️ This is a breaking change if you have begun using `fetcher.unstable_reset()`
766
767- Stabilize the `dataStrategy` `match.shouldRevalidateArgs`/`match.shouldCallHandler()` APIs. ([#14592](https://github.com/remix-run/react-router/pull/14592))
768 - The `match.shouldLoad` API is now marked deprecated in favor of these more powerful alternatives
769
770 - If you're using this API in a custom `dataStrategy` today, you can swap to the new API at your convenience:
771
772 ```tsx
773 // Before
774 const matchesToLoad = matches.filter((m) => m.shouldLoad);
775
776 // After
777 const matchesToLoad = matches.filter((m) => m.shouldCallHandler());
778 ```
779
780 - `match.shouldRevalidateArgs` is the argument that will be passed to the route `shouldRevaliate` function
781
782 - Combined with the parameter accepted by `match.shouldCallHandler`, you can define a custom revalidation behavior for your `dataStrategy`:
783
784 ```tsx
785 const matchesToLoad = matches.filter((m) => {
786 const defaultShouldRevalidate = customRevalidationBehavior(
787 match.shouldRevalidateArgs,
788 );
789 return m.shouldCallHandler(defaultShouldRevalidate);
790 // The argument here will override the internal `defaultShouldRevalidate` value
791 });
792 ```
793
794### Patch Changes
795
796- Fix a Framework Mode bug where the `defaultShouldRevalidate` parameter to `shouldRevalidate` would not be correct after `action` returned a 4xx/5xx response (`true` when it should have been `false`) ([#14592](https://github.com/remix-run/react-router/pull/14592))
797 - If your `shouldRevalidate` function relied on that parameter, you may have seen unintended revalidations
798
799- Fix `fetcher.submit` failing with plain objects containing a `tagName` property ([#14534](https://github.com/remix-run/react-router/pull/14534))
800
801- \[UNSTABLE] Add `unstable_pattern` to the parameters for client side `unstable_onError`, refactor how it's called by `RouterProvider` to avoid potential strict mode issues ([#14573](https://github.com/remix-run/react-router/pull/14573))
802
803- Add new `unstable_useTransitions` flag to routers to give users control over the usage of [`React.startTransition`](https://react.dev/reference/react/startTransition) and [`React.useOptimistic`](https://react.dev/reference/react/useOptimistic). ([#14524](https://github.com/remix-run/react-router/pull/14524))
804 - Framework Mode + Data Mode:
805 - `<HydratedRouter unstable_transition>`/`<RouterProvider unstable_transition>`
806 - When left unset (current default behavior)
807 - Router state updates are wrapped in `React.startTransition`
808 - ⚠️ This can lead to buggy behaviors if you are wrapping your own navigations/fetchers in `React.startTransition`
809 - You should set the flag to `true` if you run into this scenario to get the enhanced `useOptimistic` behavior (requires React 19)
810 - When set to `true`
811 - Router state updates remain wrapped in `React.startTransition` (as they are without the flag)
812 - `Link`/`Form` navigations will be wrapped in `React.startTransition`
813 - A subset of router state info will be surfaced to the UI _during_ navigations via `React.useOptimistic` (i.e., `useNavigation()`, `useFetchers()`, etc.)
814 - ⚠️ This is a React 19 API so you must also be React 19 to opt into this flag for Framework/Data Mode
815 - When set to `false`
816 - The router will not leverage `React.startTransition` or `React.useOptimistic` on any navigations or state changes
817 - Declarative Mode
818 - `<BrowserRouter unstable_useTransitions>`
819 - When left unset
820 - Router state updates are wrapped in `React.startTransition`
821 - When set to `true`
822 - Router state updates remain wrapped in `React.startTransition` (as they are without the flag)
823 - `Link`/`Form` navigations will be wrapped in `React.startTransition`
824 - When set to `false`
825 - the router will not leverage `React.startTransition` on any navigations or state changes
826
827- Fix the promise returned from `useNavigate` in Framework/Data Mode so that it properly tracks the duration of `popstate` navigations (i.e., `navigate(-1)`) ([#14524](https://github.com/remix-run/react-router/pull/14524))
828
829- Fix internal type error in useRoute types that surfaces when skipLibCheck is disabled ([#14577](https://github.com/remix-run/react-router/pull/14577))
830
831- Preserve `statusText` on the `ErrorResponse` instance when throwing `data()` from a route handler ([#14555](https://github.com/remix-run/react-router/pull/14555))
832
833- Optimize href() to avoid backtracking regex on splat ([#14329](https://github.com/remix-run/react-router/pull/14329))
834
835## 7.9.6
836
837### Patch Changes
838
839- \[UNSTABLE] Add `location`/`params` as arguments to client-side `unstable_onError` to permit enhanced error reporting. ([#14509](https://github.com/remix-run/react-router/pull/14509))
840
841 ⚠️ This is a breaking change if you've already adopted `unstable_onError`. The second `errorInfo` parameter is now an object with `location` and `params`:
842
843 ```tsx
844 // Before
845 function errorHandler(error: unknown, errorInfo?: React.errorInfo) {
846 /*...*/
847 }
848
849 // After
850 function errorHandler(
851 error: unknown,
852 info: {
853 location: Location;
854 params: Params;
855 errorInfo?: React.ErrorInfo;
856 },
857 ) {
858 /*...*/
859 }
860 ```
861
862- Properly handle ancestor thrown middleware errors before `next()` on fetcher submissions ([#14517](https://github.com/remix-run/react-router/pull/14517))
863
864- Fix issue with splat routes interfering with multiple calls to patchRoutesOnNavigation ([#14487](https://github.com/remix-run/react-router/pull/14487))
865
866- Normalize double-slashes in `resolvePath` ([#14529](https://github.com/remix-run/react-router/pull/14529))
867
868## 7.9.5
869
870### Patch Changes
871
872- Move RSCHydratedRouter and utils to `/dom` export. ([#14457](https://github.com/remix-run/react-router/pull/14457))
873
874- useRoute: return type-safe `handle` ([#14462](https://github.com/remix-run/react-router/pull/14462))
875
876 For example:
877
878 ```ts
879 // app/routes/admin.tsx
880 const handle = { hello: "world" };
881 ```
882
883 ```ts
884 // app/routes/some-other-route.tsx
885 export default function Component() {
886 const admin = useRoute("routes/admin");
887 if (!admin) throw new Error("Not nested within 'routes/admin'");
888 console.log(admin.handle);
889 // ^? { hello: string }
890 }
891 ```
892
893- Ensure action handlers run for routes with middleware even if no loader is present ([#14443](https://github.com/remix-run/react-router/pull/14443))
894
895- Add `unstable_instrumentations` API to allow users to add observablity to their apps by instrumenting route loaders, actions, middlewares, lazy, as well as server-side request handlers and client side navigations/fetches ([#14412](https://github.com/remix-run/react-router/pull/14412))
896 - Framework Mode:
897 - `entry.server.tsx`: `export const unstable_instrumentations = [...]`
898 - `entry.client.tsx`: `<HydratedRouter unstable_instrumentations={[...]} />`
899 - Data Mode
900 - `createBrowserRouter(routes, { unstable_instrumentations: [...] })`
901
902 This also adds a new `unstable_pattern` parameter to loaders/actions/middleware which contains the un-interpolated route pattern (i.e., `/blog/:slug`) which is useful for aggregating performance metrics by route
903
904## 7.9.4
905
906### Patch Changes
907
908- handle external redirects in from server actions ([#14400](https://github.com/remix-run/react-router/pull/14400))
909- New (unstable) `useRoute` hook for accessing data from specific routes ([#14407](https://github.com/remix-run/react-router/pull/14407))
910
911 For example, let's say you have an `admin` route somewhere in your app and you want any child routes of `admin` to all have access to the `loaderData` and `actionData` from `admin.`
912
913 ```tsx
914 // app/routes/admin.tsx
915 import { Outlet } from "react-router";
916
917 export const loader = () => ({ message: "Hello, loader!" });
918
919 export const action = () => ({ count: 1 });
920
921 export default function Component() {
922 return (
923 <div>
924 {/* ... */}
925 <Outlet />
926 {/* ... */}
927 </div>
928 );
929 }
930 ```
931
932 You might even want to create a reusable widget that all of the routes nested under `admin` could use:
933
934 ```tsx
935 import { unstable_useRoute as useRoute } from "react-router";
936
937 export function AdminWidget() {
938 // How to get `message` and `count` from `admin` route?
939 }
940 ```
941
942 In framework mode, `useRoute` knows all your app's routes and gives you TS errors when invalid route IDs are passed in:
943
944 ```tsx
945 export function AdminWidget() {
946 const admin = useRoute("routes/dmin");
947 // ^^^^^^^^^^^
948 }
949 ```
950
951 `useRoute` returns `undefined` if the route is not part of the current page:
952
953 ```tsx
954 export function AdminWidget() {
955 const admin = useRoute("routes/admin");
956 if (!admin) {
957 throw new Error(`AdminWidget used outside of "routes/admin"`);
958 }
959 }
960 ```
961
962 Note: the `root` route is the exception since it is guaranteed to be part of the current page.
963 As a result, `useRoute` never returns `undefined` for `root`.
964
965 `loaderData` and `actionData` are marked as optional since they could be accessed before the `action` is triggered or after the `loader` threw an error:
966
967 ```tsx
968 export function AdminWidget() {
969 const admin = useRoute("routes/admin");
970 if (!admin) {
971 throw new Error(`AdminWidget used outside of "routes/admin"`);
972 }
973 const { loaderData, actionData } = admin;
974 console.log(loaderData);
975 // ^? { message: string } | undefined
976 console.log(actionData);
977 // ^? { count: number } | undefined
978 }
979 ```
980
981 If instead of a specific route, you wanted access to the _current_ route's `loaderData` and `actionData`, you can call `useRoute` without arguments:
982
983 ```tsx
984 export function AdminWidget() {
985 const currentRoute = useRoute();
986 currentRoute.loaderData;
987 currentRoute.actionData;
988 }
989 ```
990
991 This usage is equivalent to calling `useLoaderData` and `useActionData`, but consolidates all route data access into one hook: `useRoute`.
992
993 Note: when calling `useRoute()` (without a route ID), TS has no way to know which route is the current route.
994 As a result, `loaderData` and `actionData` are typed as `unknown`.
995 If you want more type-safety, you can either narrow the type yourself with something like `zod` or you can refactor your app to pass down typed props to your `AdminWidget`:
996
997 ```tsx
998 export function AdminWidget({
999 message,
1000 count,
1001 }: {
1002 message: string;
1003 count: number;
1004 }) {
1005 /* ... */
1006 }
1007 ```
1008
1009## 7.9.3
1010
1011### Patch Changes
1012
1013- Do not try to use `turbo-stream` to decode CDN errors that never reached the server ([#14385](https://github.com/remix-run/react-router/pull/14385))
1014 - We used to do this but lost this check with the adoption of single fetch
1015
1016- Fix Data Mode regression causing a 404 during initial load in when `middleware` exists without any `loader` functions ([#14393](https://github.com/remix-run/react-router/pull/14393))
1017
1018## 7.9.2
1019
1020### Patch Changes
1021
1022- - Update client-side router to run client `middleware` on initial load even if no loaders exist ([#14348](https://github.com/remix-run/react-router/pull/14348))
1023 - Update `createRoutesStub` to run route middleware
1024 - You will need to set the `<RoutesStub future={{ v8_middleware: true }} />` flag to enable the proper `context` type
1025
1026- Update Lazy Route Discovery manifest requests to use a singular comma-separated `paths` query param instead of repeated `p` query params ([#14321](https://github.com/remix-run/react-router/pull/14321))
1027 - This is because Cloudflare has a hard limit of 100 URL search param key/value pairs when used as a key for caching purposes
1028 - If more that 100 paths were included, the cache key would be incomplete and could produce false-positive cache hits
1029
1030- \[UNSTABLE] Add `fetcher.unstable_reset()` API ([#14206](https://github.com/remix-run/react-router/pull/14206))
1031
1032- Made useOutlet element reference have stable identity in-between route chages ([#13382](https://github.com/remix-run/react-router/pull/13382))
1033
1034- feat: enable full transition support for the rsc router ([#14362](https://github.com/remix-run/react-router/pull/14362))
1035
1036- In RSC Data Mode, handle SSR'd client errors and re-try in the browser ([#14342](https://github.com/remix-run/react-router/pull/14342))
1037
1038- Support `middleware` prop on `<Route>` for usage with a data router via `createRoutesFromElements` ([#14357](https://github.com/remix-run/react-router/pull/14357))
1039
1040- Handle encoded question mark and hash characters in ancestor splat routes ([#14249](https://github.com/remix-run/react-router/pull/14249))
1041
1042- Fail gracefully on manifest version mismatch logic if `sessionStorage` access is blocked ([#14335](https://github.com/remix-run/react-router/pull/14335))
1043
1044## 7.9.1
1045
1046### Patch Changes
1047
1048- Fix internal `Future` interface naming from `middleware` -> `v8_middleware` ([#14327](https://github.com/remix-run/react-router/pull/14327))
1049
1050## 7.9.0
1051
1052### Minor Changes
1053
1054- Stabilize middleware and context APIs. ([#14215](https://github.com/remix-run/react-router/pull/14215))
1055
1056 We have removed the `unstable_` prefix from the following APIs and they are now considered stable and ready for production use:
1057 - [`RouterContextProvider`](https://reactrouter.com/api/utils/RouterContextProvider)
1058 - [`createContext`](https://reactrouter.com/api/utils/createContext)
1059 - `createBrowserRouter` [`getContext`](https://reactrouter.com/api/data-routers/createBrowserRouter#optsgetcontext) option
1060 - `<HydratedRouter>` [`getContext`](https://reactrouter.com/api/framework-routers/HydratedRouter#getcontext) prop
1061
1062 Please see the [Middleware Docs](https://reactrouter.com/how-to/middleware), the [Middleware RFC](https://github.com/remix-run/remix/discussions/7642), and the [Client-side Context RFC](https://github.com/remix-run/react-router/discussions/9856) for more information.
1063
1064### Patch Changes
1065
1066- Escape HTML in `meta()` JSON-LD content ([#14316](https://github.com/remix-run/react-router/pull/14316))
1067- Add react-server Await component implementation ([#14261](https://github.com/remix-run/react-router/pull/14261))
1068- In RSC Data Mode when using a custom basename, fix hydration errors for routes that only have client loaders ([#14264](https://github.com/remix-run/react-router/pull/14264))
1069- Make `href` function available in a react-server context ([#14262](https://github.com/remix-run/react-router/pull/14262))
1070- decode each time `getPayload()` is called to allow for "in-context" decoding and hoisting of contextual assets ([#14248](https://github.com/remix-run/react-router/pull/14248))
1071- `href()` now correctly processes routes that have an extension after the parameter or are a single optional parameter. ([#13797](https://github.com/remix-run/react-router/pull/13797))
1072
1073## 7.8.2
1074
1075### Patch Changes
1076
1077- \[UNSTABLE] Remove Data Mode `future.unstable_middleware` flag from `createBrowserRouter` ([#14213](https://github.com/remix-run/react-router/pull/14213))
1078 - This is only needed as a Framework Mode flag because of the route modules and the `getLoadContext` type behavior change
1079 - In Data Mode, it's an opt-in feature because it's just a new property on a route object, so there's no behavior changes that necessitate a flag
1080
1081- \[UNSTABLE] Add `<RouterProvider unstable_onError>`/`<HydratedRouter unstable_onError>` prop for client side error reporting ([#14162](https://github.com/remix-run/react-router/pull/14162))
1082
1083- server action revalidation opt out via $SKIP_REVALIDATION field ([#14154](https://github.com/remix-run/react-router/pull/14154))
1084
1085- Properly escape interpolated param values in `generatePath()` ([#13530](https://github.com/remix-run/react-router/pull/13530))
1086
1087- Maintain `ReadonlyMap` and `ReadonlySet` types in server response data. ([#13092](https://github.com/remix-run/react-router/pull/13092))
1088
1089- \[UNSTABLE] Delay serialization of `.data` redirects to 202 responses until after middleware chain ([#14205](https://github.com/remix-run/react-router/pull/14205))
1090
1091- Fix `TypeError` if you throw from `patchRoutesOnNavigation` when no partial matches exist ([#14198](https://github.com/remix-run/react-router/pull/14198))
1092
1093- Fix `basename` usage without a leading slash in data routers ([#11671](https://github.com/remix-run/react-router/pull/11671))
1094
1095- \[UNSTABLE] Update client middleware so it returns the data strategy results allowing for more advanced post-processing middleware ([#14151](https://github.com/remix-run/react-router/pull/14151))
1096
1097## 7.8.1
1098
1099### Patch Changes
1100
1101- Fix usage of optional path segments in nested routes defined using absolute paths ([#14135](https://github.com/remix-run/react-router/pull/14135))
1102- Bubble client pre-next middleware error to the shallowest ancestor that needs to load, not strictly the shallowest ancestor with a loader ([#14150](https://github.com/remix-run/react-router/pull/14150))
1103- Fix optional static segment matching in `matchPath` ([#11813](https://github.com/remix-run/react-router/pull/11813))
1104- Fix prerendering when a `basename` is set with `ssr:false` ([#13791](https://github.com/remix-run/react-router/pull/13791))
1105- Provide `isRouteErrorResponse` utility in `react-server` environments ([#14166](https://github.com/remix-run/react-router/pull/14166))
1106- Propagate non-redirect Responses thrown from middleware to the error boundary on document/data requests ([#14182](https://github.com/remix-run/react-router/pull/14182))
1107- Handle `meta` and `links` Route Exports in RSC Data Mode ([#14136](https://github.com/remix-run/react-router/pull/14136))
1108- Properly convert returned/thrown `data()` values to `Response` instances via `Response.json()` in resource routes and middleware ([#14159](https://github.com/remix-run/react-router/pull/14159), [#14181](https://github.com/remix-run/react-router/pull/14181))
1109
1110## 7.8.0
1111
1112### Minor Changes
1113
1114- Add `nonce` prop to `Links` & `PrefetchPageLinks` ([#14048](https://github.com/remix-run/react-router/pull/14048))
1115- Add `loaderData` arguments/properties alongside existing `data` arguments/properties to provide consistency and clarity between `loaderData` and `actionData` across the board ([#14047](https://github.com/remix-run/react-router/pull/14047))
1116 - Updated types: `Route.MetaArgs`, `Route.MetaMatch`, `MetaArgs`, `MetaMatch`, `Route.ComponentProps.matches`, `UIMatch`
1117 - `@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 release
1118
1119### Patch Changes
1120
1121- Prevent _"Did not find corresponding fetcher result"_ console error when navigating during a `fetcher.submit` revalidation ([#14114](https://github.com/remix-run/react-router/pull/14114))
1122
1123- Bubble client-side middleware errors prior to `next` to the appropriate ancestor error boundary ([#14138](https://github.com/remix-run/react-router/pull/14138))
1124
1125- Switch Lazy Route Discovery manifest URL generation to usea standalone `URLSearchParams` instance instead of `URL.searchParams` to avoid a major performance bottleneck in Chrome ([#14084](https://github.com/remix-run/react-router/pull/14084))
1126
1127- Adjust internal RSC usage of `React.use` to avoid Webpack compilation errors when using React 18 ([#14113](https://github.com/remix-run/react-router/pull/14113))
1128
1129- Remove dependency on `@types/node` in TypeScript declaration files ([#14059](https://github.com/remix-run/react-router/pull/14059))
1130
1131- Fix types for `UIMatch` to reflect that the `loaderData`/`data` properties may be `undefined` ([#12206](https://github.com/remix-run/react-router/pull/12206))
1132 - 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
1133 - 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
1134 - ⚠️ 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.
1135
1136 ```tsx
1137 // app/root.tsx
1138 export function loader() {
1139 someFunctionThatThrows(); // ❌ Throws an Error
1140 return { title: "My Title" };
1141 }
1142
1143 export function Layout({ children }: { children: React.ReactNode }) {
1144 let matches = useMatches();
1145 let rootMatch = matches[0] as UIMatch<Awaited<ReturnType<typeof loader>>>;
1146 // ^ rootMatch.data is incorrectly typed here, so TypeScript does not
1147 // complain if you do the following which throws an error at runtime:
1148 let { title } = rootMatch.data; // 💥
1149
1150 return <html>...</html>;
1151 }
1152 ```
1153
1154- \[UNSTABLE] Ensure resource route errors go through `handleError` w/middleware enabled ([#14078](https://github.com/remix-run/react-router/pull/14078))
1155
1156- \[UNSTABLE] Propagate returned Response from server middleware if next wasn't called ([#14093](https://github.com/remix-run/react-router/pull/14093))
1157
1158- \[UNSTABLE] Allow server middlewares to return `data()` values which will be converted into a `Response` ([#14093](https://github.com/remix-run/react-router/pull/14093))
1159
1160- \[UNSTABLE] 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](https://github.com/remix-run/react-router/pull/14118))
1161
1162- \[UNSTABLE] When middleware is enabled, make the `context` parameter read-only (via `Readonly<unstable_RouterContextProvider>`) so that TypeScript will not allow you to write arbitrary fields to it in loaders, actions, or middleware. ([#14097](https://github.com/remix-run/react-router/pull/14097))
1163
1164- \[UNSTABLE] Rename and alter the signature/functionality of the `unstable_respond` API in `staticHandler.query`/`staticHandler.queryRoute` ([#14103](https://github.com/remix-run/react-router/pull/14103))
1165 - The API has been renamed to `unstable_generateMiddlewareResponse` for clarity
1166 - 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
1167 - The `query` version of the API now has a signature of `(query: (r: Request) => Promise<StaticHandlerContext | Response>) => Promise<Response>`
1168 - The `queryRoute` version of the API now has a signature of `(queryRoute: (r: Request) => Promise<Response>) => Promise<Response>`
1169 - This allows for more advanced usages such as running logic before/after calling `query` and direct error handling of errors thrown from query
1170 - ⚠️ This is a breaking change if you've adopted the `staticHandler` `unstable_respond` API
1171
1172 ```tsx
1173 let response = await staticHandler.query(request, {
1174 requestContext: new unstable_RouterContextProvider(),
1175 async unstable_generateMiddlewareResponse(query) {
1176 try {
1177 // At this point we've run middleware top-down so we need to call the
1178 // handlers and generate the Response to bubble back up the middleware
1179 let result = await query(request);
1180 if (isResponse(result)) {
1181 return result; // Redirects, etc.
1182 }
1183 return await generateHtmlResponse(result);
1184 } catch (error: unknown) {
1185 return generateErrorResponse(error);
1186 }
1187 },
1188 });
1189 ```
1190
1191- \[UNSTABLE] Convert internal middleware implementations to use the new `unstable_generateMiddlewareResponse` API ([#14103](https://github.com/remix-run/react-router/pull/14103))
1192
1193- \[UNSTABLE] Change `getLoadContext` signature (`type GetLoadContextFunction`) when `future.unstable_middleware` is enabled so that it returns an `unstable_RouterContextProvider` instance instead of a `Map` used to contruct the instance internally ([#14097](https://github.com/remix-run/react-router/pull/14097))
1194 - This also removes the `type unstable_InitialContext` export
1195 - ⚠️ This is a breaking change if you have adopted middleware and are using a custom server with a `getLoadContext` function
1196
1197- \[UNSTABLE] Run client middleware on client navigations even if no loaders exist ([#14106](https://github.com/remix-run/react-router/pull/14106))
1198
1199- \[UNSTABLE] Change the `unstable_getContext` signature on `RouterProvider`/`HydratedRouter`/`unstable_RSCHydratedRouter` so that it returns an `unstable_RouterContextProvider` instance instead of a `Map` used to contruct the instance internally ([#14097](https://github.com/remix-run/react-router/pull/14097))
1200 - ⚠️ This is a breaking change if you have adopted the `unstable_getContext` prop
1201
1202- \[UNSTABLE] proxy server action side-effect redirects from actions for document and callServer requests ([#14131](https://github.com/remix-run/react-router/pull/14131))
1203
1204- \[UNSTABLE] Fix RSC Data Mode issue where routes that return `false` from `shouldRevalidate` would be replaced by an `<Outlet />` ([#14071](https://github.com/remix-run/react-router/pull/14071))
1205
1206## 7.7.1
1207
1208### Patch Changes
1209
1210- In RSC Data Mode, fix bug where routes with errors weren't forced to revalidate when `shouldRevalidate` returned false ([#14026](https://github.com/remix-run/react-router/pull/14026))
1211- In RSC Data Mode, fix `Matched leaf route at location "/..." does not have an element or Component` warnings when error boundaries are rendered. ([#14021](https://github.com/remix-run/react-router/pull/14021))
1212
1213## 7.7.0
1214
1215### Minor Changes
1216
1217- Add unstable RSC support ([#13700](https://github.com/remix-run/react-router/pull/13700))
1218
1219 For more information, see the [RSC documentation](https://reactrouter.com/start/rsc/installation).
1220
1221### Patch Changes
1222
1223- Handle `InvalidCharacterError` when validating cookie signature ([#13847](https://github.com/remix-run/react-router/pull/13847))
1224
1225- Pass a copy of `searchParams` to the `setSearchParams` callback function to avoid muations of the internal `searchParams` instance. This was an issue when navigations were blocked because the internal instance be out of sync with `useLocation().search`. ([#12784](https://github.com/remix-run/react-router/pull/12784))
1226
1227- Support invalid `Date` in `turbo-stream` v2 fork ([#13684](https://github.com/remix-run/react-router/pull/13684))
1228
1229- In Framework Mode, clear critical CSS in development after initial render ([#13872](https://github.com/remix-run/react-router/pull/13872))
1230
1231- Strip search parameters from `patchRoutesOnNavigation` `path` param for fetcher calls ([#13911](https://github.com/remix-run/react-router/pull/13911))
1232
1233- Skip scroll restoration on useRevalidator() calls because they're not new locations ([#13671](https://github.com/remix-run/react-router/pull/13671))
1234
1235- Support unencoded UTF-8 routes in prerender config with `ssr` set to `false` ([#13699](https://github.com/remix-run/react-router/pull/13699))
1236
1237- Do not throw if the url hash is not a valid URI component ([#13247](https://github.com/remix-run/react-router/pull/13247))
1238
1239- Fix a regression in `createRoutesStub` introduced with the middleware feature. ([#13946](https://github.com/remix-run/react-router/pull/13946))
1240
1241 As part of that work we altered the signature to align with the new middleware APIs without making it backwards compatible with the prior `AppLoadContext` API. This permitted `createRoutesStub` to work if you were opting into middleware and the updated `context` typings, but broke `createRoutesStub` for users not yet opting into middleware.
1242
1243 We've reverted this change and re-implemented it in such a way that both sets of users can leverage it.
1244
1245 ```tsx
1246 // If you have not opted into middleware, the old API should work again
1247 let context: AppLoadContext = {
1248 /*...*/
1249 };
1250 let Stub = createRoutesStub(routes, context);
1251
1252 // If you have opted into middleware, you should now pass an instantiated `unstable_routerContextProvider` instead of a `getContext` factory function.
1253 let context = new unstable_RouterContextProvider();
1254 context.set(SomeContext, someValue);
1255 let Stub = createRoutesStub(routes, context);
1256 ```
1257
1258 ⚠️ This may be a breaking bug for if you have adopted the unstable Middleware feature and are using `createRoutesStub` with the updated API.
1259
1260- Remove `Content-Length` header from Single Fetch responses ([#13902](https://github.com/remix-run/react-router/pull/13902))
1261
1262## 7.6.3
1263
1264### Patch Changes
1265
1266- Do not serialize types for `useRouteLoaderData<typeof clientLoader>` ([#13752](https://github.com/remix-run/react-router/pull/13752))
1267
1268 For types to distinguish a `clientLoader` from a `serverLoader`, you MUST annotate `clientLoader` args:
1269
1270 ```ts
1271 // 👇 annotation required to skip serializing types
1272 export function clientLoader({}: Route.ClientLoaderArgs) {
1273 return { fn: () => "earth" };
1274 }
1275
1276 function SomeComponent() {
1277 const data = useRouteLoaderData<typeof clientLoader>("routes/this-route");
1278 const planet = data?.fn() ?? "world";
1279 return <h1>Hello, {planet}!</h1>;
1280 }
1281 ```
1282
1283## 7.6.2
1284
1285### Patch Changes
1286
1287- Avoid additional `with-props` chunk in Framework Mode by moving route module component prop logic from the Vite plugin to `react-router` ([#13650](https://github.com/remix-run/react-router/pull/13650))
1288- Slight refactor of internal `headers()` function processing for use with RSC ([#13639](https://github.com/remix-run/react-router/pull/13639))
1289
1290## 7.6.1
1291
1292### Patch Changes
1293
1294- Update `Route.MetaArgs` to reflect that `data` can be potentially `undefined` ([#13563](https://github.com/remix-run/react-router/pull/13563))
1295
1296 This is primarily for cases where a route `loader` threw an error to it's own `ErrorBoundary`. but it also arises in the case of a 404 which renders the root `ErrorBoundary`/`meta` but the root loader did not run because not routes matched.
1297
1298- Partially revert optimization added in `7.1.4` to reduce calls to `matchRoutes` because it surfaced other issues ([#13562](https://github.com/remix-run/react-router/pull/13562))
1299
1300- Fix typegen when same route is used at multiple paths ([#13574](https://github.com/remix-run/react-router/pull/13574))
1301
1302 For example, `routes/route.tsx` is used at 4 different paths here:
1303
1304 ```ts
1305 import { type RouteConfig, route } from "@react-router/dev/routes";
1306 export default [
1307 route("base/:base", "routes/base.tsx", [
1308 route("home/:home", "routes/route.tsx", { id: "home" }),
1309 route("changelog/:changelog", "routes/route.tsx", { id: "changelog" }),
1310 route("splat/*", "routes/route.tsx", { id: "splat" }),
1311 ]),
1312 route("other/:other", "routes/route.tsx", { id: "other" }),
1313 ] satisfies RouteConfig;
1314 ```
1315
1316 Previously, typegen would arbitrarily pick one of these paths to be the "winner" and generate types for the route module based on that path.
1317 Now, typegen creates unions as necessary for alternate paths for the same route file.
1318
1319- Better types for `params` ([#13543](https://github.com/remix-run/react-router/pull/13543))
1320
1321 For example:
1322
1323 ```ts
1324 // routes.ts
1325 import { type RouteConfig, route } from "@react-router/dev/routes";
1326
1327 export default [
1328 route("parent/:p", "routes/parent.tsx", [
1329 route("layout/:l", "routes/layout.tsx", [
1330 route("child1/:c1a/:c1b", "routes/child1.tsx"),
1331 route("child2/:c2a/:c2b", "routes/child2.tsx"),
1332 ]),
1333 ]),
1334 ] satisfies RouteConfig;
1335 ```
1336
1337 Previously, `params` for the `routes/layout.tsx` route were calculated as `{ p: string, l: string }`.
1338 This incorrectly ignores params that could come from child routes.
1339 If visiting `/parent/1/layout/2/child1/3/4`, the actual params passed to `routes/layout.tsx` will have a type of `{ p: string, l: string, c1a: string, c1b: string }`.
1340
1341 Now, `params` are aware of child routes and autocompletion will include child params as optionals:
1342
1343 ```ts
1344 params.|
1345 // ^ cursor is here and you ask for autocompletion
1346 // p: string
1347 // l: string
1348 // c1a?: string
1349 // c1b?: string
1350 // c2a?: string
1351 // c2b?: string
1352 ```
1353
1354 You can also narrow the types for `params` as it is implemented as a normalized union of params for each page that includes `routes/layout.tsx`:
1355
1356 ```ts
1357 if (typeof params.c1a === 'string') {
1358 params.|
1359 // ^ cursor is here and you ask for autocompletion
1360 // p: string
1361 // l: string
1362 // c1a: string
1363 // c1b: string
1364 }
1365 ```
1366
1367 ***
1368
1369 UNSTABLE: renamed internal `react-router/route-module` export to `react-router/internal`
1370 UNSTABLE: removed `Info` export from generated `+types/*` files
1371
1372- Avoid initial fetcher execution 404 error when Lazy Route Discovery is interrupted by a navigation ([#13564](https://github.com/remix-run/react-router/pull/13564))
1373
1374- href replaces splats `*` ([#13593](https://github.com/remix-run/react-router/pull/13593))
1375
1376 ```ts
1377 const a = href("/products/*", { "*": "/1/edit" });
1378 // -> /products/1/edit
1379 ```
1380
1381## 7.6.0
1382
1383### Minor Changes
1384
1385- Added a new `react-router.config.ts` `routeDiscovery` option to configure Lazy Route Discovery behavior. ([#13451](https://github.com/remix-run/react-router/pull/13451))
1386 - By default, Lazy Route Discovery is enabled and makes manifest requests to the `/__manifest` path:
1387 - `routeDiscovery: { mode: "lazy", manifestPath: "/__manifest" }`
1388 - You can modify the manifest path used:
1389 - `routeDiscovery: { mode: "lazy", manifestPath: "/custom-manifest" }`
1390 - Or you can disable this feature entirely and include all routes in the manifest on initial document load:
1391 - `routeDiscovery: { mode: "initial" }`
1392
1393- Add support for route component props in `createRoutesStub`. This allows you to unit test your route components using the props instead of the hooks: ([#13528](https://github.com/remix-run/react-router/pull/13528))
1394
1395 ```tsx
1396 let RoutesStub = createRoutesStub([
1397 {
1398 path: "/",
1399 Component({ loaderData }) {
1400 let data = loaderData as { message: string };
1401 return <pre data-testid="data">Message: {data.message}</pre>;
1402 },
1403 loader() {
1404 return { message: "hello" };
1405 },
1406 },
1407 ]);
1408
1409 render(<RoutesStub />);
1410
1411 await waitFor(() => screen.findByText("Message: hello"));
1412 ```
1413
1414### Patch Changes
1415
1416- Fix `react-router` module augmentation for `NodeNext` ([#13498](https://github.com/remix-run/react-router/pull/13498))
1417
1418- Don't bundle `react-router` in `react-router/dom` CJS export ([#13497](https://github.com/remix-run/react-router/pull/13497))
1419
1420- Fix bug where a submitting `fetcher` would get stuck in a `loading` state if a revalidating `loader` redirected ([#12873](https://github.com/remix-run/react-router/pull/12873))
1421
1422- Fix hydration error if a server `loader` returned `undefined` ([#13496](https://github.com/remix-run/react-router/pull/13496))
1423
1424- Fix initial load 404 scenarios in data mode ([#13500](https://github.com/remix-run/react-router/pull/13500))
1425
1426- Stabilize `useRevalidator`'s `revalidate` function ([#13542](https://github.com/remix-run/react-router/pull/13542))
1427
1428- Preserve status code if a `clientAction` throws a `data()` result in framework mode ([#13522](https://github.com/remix-run/react-router/pull/13522))
1429
1430- Be defensive against leading double slashes in paths to avoid `Invalid URL` errors from the URL constructor ([#13510](https://github.com/remix-run/react-router/pull/13510))
1431 - Note we do not sanitize/normalize these paths - we only detect them so we can avoid the error that would be thrown by `new URL("//", window.location.origin)`
1432
1433- Remove `Navigator` declaration for `navigator.connection.saveData` to avoid messing with any other types beyond `saveData` in userland ([#13512](https://github.com/remix-run/react-router/pull/13512))
1434
1435- Fix `handleError` `params` values on `.data` requests for routes with a dynamic param as the last URL segment ([#13481](https://github.com/remix-run/react-router/pull/13481))
1436
1437- Don't trigger an `ErrorBoundary` UI before the reload when we detect a manifest verison mismatch in Lazy Route Discovery ([#13480](https://github.com/remix-run/react-router/pull/13480))
1438
1439- Inline `turbo-stream@2.4.1` dependency and fix decoding ordering of Map/Set instances ([#13518](https://github.com/remix-run/react-router/pull/13518))
1440
1441- Only render dev warnings in DEV mode ([#13461](https://github.com/remix-run/react-router/pull/13461))
1442
1443- UNSTABLE: Fix a few bugs with error bubbling in middleware use-cases ([#13538](https://github.com/remix-run/react-router/pull/13538))
1444
1445- Short circuit post-processing on aborted `dataStrategy` requests ([#13521](https://github.com/remix-run/react-router/pull/13521))
1446 - This resolves non-user-facing console errors of the form `Cannot read properties of undefined (reading 'result')`
1447
1448## 7.5.3
1449
1450### Patch Changes
1451
1452- Fix bug where bubbled action errors would result in `loaderData` being cleared at the handling `ErrorBoundary` route ([#13476](https://github.com/remix-run/react-router/pull/13476))
1453- Handle redirects from `clientLoader.hydrate` initial load executions ([#13477](https://github.com/remix-run/react-router/pull/13477))
1454
1455## 7.5.2
1456
1457### Patch Changes
1458
1459- Update Single Fetch to also handle the 204 redirects used in `?_data` requests in Remix v2 ([#13364](https://github.com/remix-run/react-router/pull/13364))
1460 - This allows applications to return a redirect on `.data` requests from outside the scope of React Router (i.e., an `express`/`hono` middleware)
1461 - ⚠️ Please note that doing so relies on implementation details that are subject to change without a SemVer major release
1462 - This is primarily done to ease upgrading to Single Fetch for existing Remix v2 applications, but the recommended way to handle this is redirecting from a route middleware
1463
1464- Adjust approach for Prerendering/SPA Mode via headers ([#13453](https://github.com/remix-run/react-router/pull/13453))
1465
1466## 7.5.1
1467
1468### Patch Changes
1469
1470- Fix single fetch bug where no revalidation request would be made when navigating upwards to a reused parent route ([#13253](https://github.com/remix-run/react-router/pull/13253))
1471
1472- When using the object-based `route.lazy` API, the `HydrateFallback` and `hydrateFallbackElement` properties are now skipped when lazy loading routes after hydration. ([#13376](https://github.com/remix-run/react-router/pull/13376))
1473
1474 If you move the code for these properties into a separate file, you can use this optimization to avoid downloading unused hydration code. For example:
1475
1476 ```ts
1477 createBrowserRouter([
1478 {
1479 path: "/show/:showId",
1480 lazy: {
1481 loader: async () => (await import("./show.loader.js")).loader,
1482 Component: async () => (await import("./show.component.js")).Component,
1483 HydrateFallback: async () =>
1484 (await import("./show.hydrate-fallback.js")).HydrateFallback,
1485 },
1486 },
1487 ]);
1488 ```
1489
1490- Properly revalidate prerendered paths when param values change ([#13380](https://github.com/remix-run/react-router/pull/13380))
1491
1492- UNSTABLE: Add a new `unstable_runClientMiddleware` argument to `dataStrategy` to enable middleware execution in custom `dataStrategy` implementations ([#13395](https://github.com/remix-run/react-router/pull/13395))
1493
1494- UNSTABLE: Add better error messaging when `getLoadContext` is not updated to return a `Map`" ([#13242](https://github.com/remix-run/react-router/pull/13242))
1495
1496- Do not automatically add `null` to `staticHandler.query()` `context.loaderData` if routes do not have loaders ([#13223](https://github.com/remix-run/react-router/pull/13223))
1497 - This was a Remix v2 implementation detail inadvertently left in for React Router v7
1498 - Now that we allow returning `undefined` from loaders, our prior check of `loaderData[routeId] !== undefined` was no longer sufficient and was changed to a `routeId in loaderData` check - these `null` values can cause issues for this new check
1499 - ⚠️ This could be a "breaking bug fix" for you if you are doing manual SSR with `createStaticHandler()`/`<StaticRouterProvider>`, and using `context.loaderData` to control `<RouterProvider>` hydration behavior on the client
1500
1501- Fix prerendering when a loader returns a redirect ([#13365](https://github.com/remix-run/react-router/pull/13365))
1502
1503- UNSTABLE: Update context type for `LoaderFunctionArgs`/`ActionFunctionArgs` when middleware is enabled ([#13381](https://github.com/remix-run/react-router/pull/13381))
1504
1505- Add support for the new `unstable_shouldCallHandler`/`unstable_shouldRevalidateArgs` APIs in `dataStrategy` ([#13253](https://github.com/remix-run/react-router/pull/13253))
1506
1507## 7.5.0
1508
1509### Minor Changes
1510
1511- Add granular object-based API for `route.lazy` to support lazy loading of individual route properties, for example: ([#13294](https://github.com/remix-run/react-router/pull/13294))
1512
1513 ```ts
1514 createBrowserRouter([
1515 {
1516 path: "/show/:showId",
1517 lazy: {
1518 loader: async () => (await import("./show.loader.js")).loader,
1519 action: async () => (await import("./show.action.js")).action,
1520 Component: async () => (await import("./show.component.js")).Component,
1521 },
1522 },
1523 ]);
1524 ```
1525
1526 **Breaking change for `route.unstable_lazyMiddleware` consumers**
1527
1528 The `route.unstable_lazyMiddleware` property is no longer supported. If you want to lazily load middleware, you must use the new object-based `route.lazy` API with `route.lazy.unstable_middleware`, for example:
1529
1530 ```ts
1531 createBrowserRouter([
1532 {
1533 path: "/show/:showId",
1534 lazy: {
1535 unstable_middleware: async () =>
1536 (await import("./show.middleware.js")).middleware,
1537 // etc.
1538 },
1539 },
1540 ]);
1541 ```
1542
1543### Patch Changes
1544
1545- Introduce `unstable_subResourceIntegrity` future flag that enables generation of an importmap with integrity for the scripts that will be loaded by the browser. ([#13163](https://github.com/remix-run/react-router/pull/13163))
1546
1547## 7.4.1
1548
1549### Patch Changes
1550
1551- Fix types on `unstable_MiddlewareFunction` to avoid type errors when a middleware doesn't return a value ([#13311](https://github.com/remix-run/react-router/pull/13311))
1552- Dedupe calls to `route.lazy` functions ([#13260](https://github.com/remix-run/react-router/pull/13260))
1553- Add support for `route.unstable_lazyMiddleware` function to allow lazy loading of middleware logic. ([#13210](https://github.com/remix-run/react-router/pull/13210))
1554
1555 **Breaking change for `unstable_middleware` consumers**
1556
1557 The `route.unstable_middleware` property is no longer supported in the return value from `route.lazy`. If you want to lazily load middleware, you must use `route.unstable_lazyMiddleware`.
1558
1559## 7.4.0
1560
1561### Patch Changes
1562
1563- Fix root loader data on initial load redirects in SPA mode ([#13222](https://github.com/remix-run/react-router/pull/13222))
1564- Load ancestor pathless/index routes in lazy route discovery for upwards non-eager-discoery routing ([#13203](https://github.com/remix-run/react-router/pull/13203))
1565- Fix `shouldRevalidate` behavior for `clientLoader`-only routes in `ssr:true` apps ([#13221](https://github.com/remix-run/react-router/pull/13221))
1566- UNSTABLE: Fix `RequestHandler` `loadContext` parameter type when middleware is enabled ([#13204](https://github.com/remix-run/react-router/pull/13204))
1567- UNSTABLE: Update `Route.unstable_MiddlewareFunction` to have a return value of `Response | undefined` instead of `Response | void` becaue you should not return anything if you aren't returning the `Response` ([#13199](https://github.com/remix-run/react-router/pull/13199))
1568- UNSTABLE(BREAKING): If a middleware throws an error, ensure we only bubble the error itself via `next()` and are no longer leaking the `MiddlewareError` implementation detail ([#13180](https://github.com/remix-run/react-router/pull/13180))
1569
1570## 7.3.0
1571
1572### Minor Changes
1573
1574- Add `fetcherKey` as a parameter to `patchRoutesOnNavigation` ([#13061](https://github.com/remix-run/react-router/pull/13061))
1575 - In framework mode, Lazy Route Discovery will now detect manifest version mismatches after a new deploy
1576 - On navigations to undiscovered routes, this mismatch will trigger a document reload of the destination path
1577 - On `fetcher` calls to undiscovered routes, this mismatch will trigger a document reload of the current path
1578
1579### Patch Changes
1580
1581- Skip resource route flow in dev server in SPA mode ([#13113](https://github.com/remix-run/react-router/pull/13113))
1582
1583- Support middleware on routes (unstable) ([#12941](https://github.com/remix-run/react-router/pull/12941))
1584
1585 Middleware is implemented behind a `future.unstable_middleware` flag. To enable, you must enable the flag and the types in your `react-router-config.ts` file:
1586
1587 ```ts
1588 import type { Config } from "@react-router/dev/config";
1589 import type { Future } from "react-router";
1590
1591 declare module "react-router" {
1592 interface Future {
1593 unstable_middleware: true; // 👈 Enable middleware types
1594 }
1595 }
1596
1597 export default {
1598 future: {
1599 unstable_middleware: true, // 👈 Enable middleware
1600 },
1601 } satisfies Config;
1602 ```
1603
1604 ⚠️ Middleware is unstable and should not be adopted in production. There is at least one known de-optimization in route module loading for `clientMiddleware` that we will be addressing this before a stable release.
1605
1606 ⚠️ Enabling middleware contains a breaking change to the `context` parameter passed to your `loader`/`action` functions - see below for more information.
1607
1608 Once enabled, routes can define an array of middleware functions that will run sequentially before route handlers run. These functions accept the same parameters as `loader`/`action` plus an additional `next` parameter to run the remaining data pipeline. This allows middlewares to perform logic before and after handlers execute.
1609
1610 ```tsx
1611 // Framework mode
1612 export const unstable_middleware = [serverLogger, serverAuth]; // server
1613 export const unstable_clientMiddleware = [clientLogger]; // client
1614
1615 // Library mode
1616 const routes = [
1617 {
1618 path: "/",
1619 // Middlewares are client-side for library mode SPA's
1620 unstable_middleware: [clientLogger, clientAuth],
1621 loader: rootLoader,
1622 Component: Root,
1623 },
1624 ];
1625 ```
1626
1627 Here's a simple example of a client-side logging middleware that can be placed on the root route:
1628
1629 ```tsx
1630 const clientLogger: Route.unstable_ClientMiddlewareFunction = async (
1631 { request },
1632 next,
1633 ) => {
1634 let start = performance.now();
1635
1636 // Run the remaining middlewares and all route loaders
1637 await next();
1638
1639 let duration = performance.now() - start;
1640 console.log(`Navigated to ${request.url} (${duration}ms)`);
1641 };
1642 ```
1643
1644 Note that in the above example, the `next`/`middleware` functions don't return anything. This is by design as on the client there is no "response" to send over the network like there would be for middlewares running on the server. The data is all handled behind the scenes by the stateful `router`.
1645
1646 For a server-side middleware, the `next` function will return the HTTP `Response` that React Router will be sending across the wire, thus giving you a chance to make changes as needed. You may throw a new response to short circuit and respond immediately, or you may return a new or altered response to override the default returned by `next()`.
1647
1648 ```tsx
1649 const serverLogger: Route.unstable_MiddlewareFunction = async (
1650 { request, params, context },
1651 next,
1652 ) => {
1653 let start = performance.now();
1654
1655 // 👇 Grab the response here
1656 let res = await next();
1657
1658 let duration = performance.now() - start;
1659 console.log(`Navigated to ${request.url} (${duration}ms)`);
1660
1661 // 👇 And return it here (optional if you don't modify the response)
1662 return res;
1663 };
1664 ```
1665
1666 You can throw a `redirect` from a middleware to short circuit any remaining processing:
1667
1668 ```tsx
1669 import { sessionContext } from "../context";
1670 const serverAuth: Route.unstable_MiddlewareFunction = (
1671 { request, params, context },
1672 next,
1673 ) => {
1674 let session = context.get(sessionContext);
1675 let user = session.get("user");
1676 if (!user) {
1677 session.set("returnTo", request.url);
1678 throw redirect("/login", 302);
1679 }
1680 };
1681 ```
1682
1683 _Note that in cases like this where you don't need to do any post-processing you don't need to call the `next` function or return a `Response`._
1684
1685 Here's another example of using a server middleware to detect 404s and check the CMS for a redirect:
1686
1687 ```tsx
1688 const redirects: Route.unstable_MiddlewareFunction = async ({
1689 request,
1690 next,
1691 }) => {
1692 // attempt to handle the request
1693 let res = await next();
1694
1695 // if it's a 404, check the CMS for a redirect, do it last
1696 // because it's expensive
1697 if (res.status === 404) {
1698 let cmsRedirect = await checkCMSRedirects(request.url);
1699 if (cmsRedirect) {
1700 throw redirect(cmsRedirect, 302);
1701 }
1702 }
1703
1704 return res;
1705 };
1706 ```
1707
1708 **`context` parameter**
1709
1710 When middleware is enabled, your application will use a different type of `context` parameter in your loaders and actions to provide better type safety. Instead of `AppLoadContext`, `context` will now be an instance of `ContextProvider` that you can use with type-safe contexts (similar to `React.createContext`):
1711
1712 ```ts
1713 import { unstable_createContext } from "react-router";
1714 import { Route } from "./+types/root";
1715 import type { Session } from "./sessions.server";
1716 import { getSession } from "./sessions.server";
1717
1718 let sessionContext = unstable_createContext<Session>();
1719
1720 const sessionMiddleware: Route.unstable_MiddlewareFunction = ({
1721 context,
1722 request,
1723 }) => {
1724 let session = await getSession(request);
1725 context.set(sessionContext, session);
1726 // ^ must be of type Session
1727 };
1728
1729 // ... then in some downstream middleware
1730 const loggerMiddleware: Route.unstable_MiddlewareFunction = ({
1731 context,
1732 request,
1733 }) => {
1734 let session = context.get(sessionContext);
1735 // ^ typeof Session
1736 console.log(session.get("userId"), request.method, request.url);
1737 };
1738
1739 // ... or some downstream loader
1740 export function loader({ context }: Route.LoaderArgs) {
1741 let session = context.get(sessionContext);
1742 let profile = await getProfile(session.get("userId"));
1743 return { profile };
1744 }
1745 ```
1746
1747 If you are using a custom server with a `getLoadContext` function, the return value for initial context values passed from the server adapter layer is no longer an object and should now return an `unstable_InitialContext` (`Map<RouterContext, unknown>`):
1748
1749 ```ts
1750 let adapterContext = unstable_createContext<MyAdapterContext>();
1751
1752 function getLoadContext(req, res): unstable_InitialContext {
1753 let map = new Map();
1754 map.set(adapterContext, getAdapterContext(req));
1755 return map;
1756 }
1757 ```
1758
1759- Fix types for loaderData and actionData that contained `Record`s ([#13139](https://github.com/remix-run/react-router/pull/13139))
1760
1761 UNSTABLE(BREAKING):
1762
1763 `unstable_SerializesTo` added a way to register custom serialization types in Single Fetch for other library and framework authors like Apollo.
1764 It was implemented with branded type whose branded property that was made optional so that casting arbitrary values was easy:
1765
1766 ```ts
1767 // without the brand being marked as optional
1768 let x1 = 42 as unknown as unstable_SerializesTo<number>;
1769 // ^^^^^^^^^^
1770
1771 // with the brand being marked as optional
1772 let x2 = 42 as unstable_SerializesTo<number>;
1773 ```
1774
1775 However, this broke type inference in `loaderData` and `actionData` for any `Record` types as those would now (incorrectly) match `unstable_SerializesTo`.
1776 This affected all users, not just those that depended on `unstable_SerializesTo`.
1777 To fix this, the branded property of `unstable_SerializesTo` is marked as required instead of optional.
1778
1779 For library and framework authors using `unstable_SerializesTo`, you may need to add `as unknown` casts before casting to `unstable_SerializesTo`.
1780
1781- Fix single fetch `_root.data` requests when a `basename` is used ([#12898](https://github.com/remix-run/react-router/pull/12898))
1782
1783- Add `context` support to client side data routers (unstable) ([#12941](https://github.com/remix-run/react-router/pull/12941))
1784
1785 Your application `loader` and `action` functions on the client will now receive a `context` parameter. This is an instance of `unstable_RouterContextProvider` that you use with type-safe contexts (similar to `React.createContext`) and is most useful with the corresponding `middleware`/`clientMiddleware` API's:
1786
1787 ```ts
1788 import { unstable_createContext } from "react-router";
1789
1790 type User = {
1791 /*...*/
1792 };
1793
1794 let userContext = unstable_createContext<User>();
1795
1796 function sessionMiddleware({ context }) {
1797 let user = await getUser();
1798 context.set(userContext, user);
1799 }
1800
1801 // ... then in some downstream loader
1802 function loader({ context }) {
1803 let user = context.get(userContext);
1804 let profile = await getProfile(user.id);
1805 return { profile };
1806 }
1807 ```
1808
1809 Similar to server-side requests, a fresh `context` will be created per navigation (or `fetcher` call). If you have initial data you'd like to populate in the context for every request, you can provide an `unstable_getContext` function at the root of your app:
1810 - Library mode - `createBrowserRouter(routes, { unstable_getContext })`
1811 - Framework mode - `<HydratedRouter unstable_getContext>`
1812
1813 This function should return an value of type `unstable_InitialContext` which is a `Map<unstable_RouterContext, unknown>` of context's and initial values:
1814
1815 ```ts
1816 const loggerContext = unstable_createContext<(...args: unknown[]) => void>();
1817
1818 function logger(...args: unknown[]) {
1819 console.log(new Date.toISOString(), ...args);
1820 }
1821
1822 function unstable_getContext() {
1823 let map = new Map();
1824 map.set(loggerContext, logger);
1825 return map;
1826 }
1827 ```
1828
1829## 7.2.0
1830
1831### Minor Changes
1832
1833- New type-safe `href` utility that guarantees links point to actual paths in your app ([#13012](https://github.com/remix-run/react-router/pull/13012))
1834
1835 ```tsx
1836 import { href } from "react-router";
1837
1838 export default function Component() {
1839 const link = href("/blog/:slug", { slug: "my-first-post" });
1840 return (
1841 <main>
1842 <Link to={href("/products/:id", { id: "asdf" })} />
1843 <NavLink to={href("/:lang?/about", { lang: "en" })} />
1844 </main>
1845 );
1846 }
1847 ```
1848
1849### Patch Changes
1850
1851- Fix typegen for repeated params ([#13012](https://github.com/remix-run/react-router/pull/13012))
1852
1853 In React Router, path parameters are keyed by their name.
1854 So for a path pattern like `/a/:id/b/:id?/c/:id`, the last `:id` will set the value for `id` in `useParams` and the `params` prop.
1855 For example, `/a/1/b/2/c/3` will result in the value `{ id: 3 }` at runtime.
1856
1857 Previously, generated types for params incorrectly modeled repeated params with an array.
1858 So `/a/1/b/2/c/3` generated a type like `{ id: [1,2,3] }`.
1859
1860 To be consistent with runtime behavior, the generated types now correctly model the "last one wins" semantics of path parameters.
1861 So `/a/1/b/2/c/3` now generates a type like `{ id: 3 }`.
1862
1863- Don't apply Single Fetch revalidation de-optimization when in SPA mode since there is no server HTTP request ([#12948](https://github.com/remix-run/react-router/pull/12948))
1864
1865- Properly handle revalidations to across a prerender/SPA boundary ([#13021](https://github.com/remix-run/react-router/pull/13021))
1866 - In "hybrid" applications where some routes are pre-rendered and some are served from a SPA fallback, we need to avoid making `.data` requests if the path wasn't pre-rendered because the request will 404
1867 - We don't know all the pre-rendered paths client-side, however:
1868 - All `loader` data in `ssr:false` mode is static because it's generated at build time
1869 - A route must use a `clientLoader` to do anything dynamic
1870 - Therefore, if a route only has a `loader` and not a `clientLoader`, we disable revalidation by default because there is no new data to retrieve
1871 - We short circuit and skip single fetch `.data` request logic if there are no server loaders with `shouldLoad=true` in our single fetch `dataStrategy`
1872 - This ensures that the route doesn't cause a `.data` request that would 404 after a submission
1873
1874- Error at build time in `ssr:false` + `prerender` apps for the edge case scenario of: ([#13021](https://github.com/remix-run/react-router/pull/13021))
1875 - A parent route has only a `loader` (does not have a `clientLoader`)
1876 - The parent route is pre-rendered
1877 - The parent route has children routes which are not prerendered
1878 - This means that when the child paths are loaded via the SPA fallback, the parent won't have any `loaderData` because there is no server on which to run the `loader`
1879 - This can be resolved by either adding a parent `clientLoader` or pre-rendering the child paths
1880 - If you add a `clientLoader`, calling the `serverLoader()` on non-prerendered paths will throw a 404
1881
1882- Add unstable support for splitting route modules in framework mode via `future.unstable_splitRouteModules` ([#11871](https://github.com/remix-run/react-router/pull/11871))
1883
1884- Add `unstable_SerializesTo` brand type for library authors to register types serializable by React Router's streaming format (`turbo-stream`) ([`ab5b05b02`](https://github.com/remix-run/react-router/commit/ab5b05b02f99f062edb3c536c392197c88eb6c77))
1885
1886- Align dev server behavior with static file server behavior when `ssr:false` is set ([#12948](https://github.com/remix-run/react-router/pull/12948))
1887 - When no `prerender` config exists, only SSR down to the root `HydrateFallback` (SPA Mode)
1888 - When a `prerender` config exists but the current path is not prerendered, only SSR down to the root `HydrateFallback` (SPA Fallback)
1889 - Return a 404 on `.data` requests to non-pre-rendered paths
1890
1891- Improve prefetch performance of CSS side effects in framework mode ([#12889](https://github.com/remix-run/react-router/pull/12889))
1892
1893- Disable Lazy Route Discovery for all `ssr:false` apps and not just "SPA Mode" because there is no runtime server to serve the search-param-configured `__manifest` requests ([#12894](https://github.com/remix-run/react-router/pull/12894))
1894 - We previously only disabled this for "SPA Mode" which is `ssr:false` and no `prerender` config but we realized it should apply to all `ssr:false` apps, including those prerendering multiple pages
1895 - In those `prerender` scenarios we would prerender the `/__manifest` file assuming the static file server would serve it but that makes some unneccesary assumptions about the static file server behaviors
1896
1897- Properly handle interrupted manifest requests in lazy route discovery ([#12915](https://github.com/remix-run/react-router/pull/12915))
1898
1899## 7.1.5
1900
1901### Patch Changes
1902
1903- Fix regression introduced in `7.1.4` via [#12800](https://github.com/remix-run/react-router/pull/12800) that caused issues navigating to hash routes inside splat routes for applications using Lazy Route Discovery (`patchRoutesOnNavigation`) ([#12927](https://github.com/remix-run/react-router/pull/12927))
1904
1905## 7.1.4
1906
1907### Patch Changes
1908
1909- Internal reorg to clean up some duplicated route module types ([#12799](https://github.com/remix-run/react-router/pull/12799))
1910- Properly handle status codes that cannot have a body in single fetch responses (204, etc.) ([#12760](https://github.com/remix-run/react-router/pull/12760))
1911- Stop erroring on resource routes that return raw strings/objects and instead serialize them as `text/plain` or `application/json` responses ([#12848](https://github.com/remix-run/react-router/pull/12848))
1912 - This only applies when accessed as a resource route without the `.data` extension
1913 - When accessed from a Single Fetch `.data` request, they will still be encoded via `turbo-stream`
1914- Optimize Lazy Route Discovery path discovery to favor a single `querySelectorAll` call at the `body` level instead of many calls at the sub-tree level ([#12731](https://github.com/remix-run/react-router/pull/12731))
1915- Properly bubble headers as `errorHeaders` when throwing a `data()` result ([#12846](https://github.com/remix-run/react-router/pull/12846))
1916 - Avoid duplication of `Set-Cookie` headers could be duplicated if also returned from `headers`
1917- Optimize route matching by skipping redundant `matchRoutes` calls when possible ([#12800](https://github.com/remix-run/react-router/pull/12800))
1918
1919## 7.1.3
1920
1921_No changes_
1922
1923## 7.1.2
1924
1925### Patch Changes
1926
1927- Fix issue with fetcher data cleanup in the data layer on fetcher unmount ([#12681](https://github.com/remix-run/react-router/pull/12681))
1928- Do not rely on `symbol` for filtering out `redirect` responses from loader data ([#12694](https://github.com/remix-run/react-router/pull/12694))
1929
1930 Previously, some projects were getting type checking errors like:
1931
1932 ```ts
1933 error TS4058: Return type of exported function has or is using name 'redirectSymbol' from external module "node_modules/..." but cannot be named.
1934 ```
1935
1936 Now that `symbol`s are not used for the `redirect` response type, these errors should no longer be present.
1937
1938## 7.1.1
1939
1940_No changes_
1941
1942## 7.1.0
1943
1944### Patch Changes
1945
1946- Throw unwrapped single fetch redirect to align with pre-single fetch behavior ([#12506](https://github.com/remix-run/react-router/pull/12506))
1947- Ignore redirects when inferring loader data types ([#12527](https://github.com/remix-run/react-router/pull/12527))
1948- Remove `<Link prefetch>` warning which suffers from false positives in a lazy route discovery world ([#12485](https://github.com/remix-run/react-router/pull/12485))
1949
1950## 7.0.2
1951
1952### Patch Changes
1953
1954- temporarily only use one build in export map so packages can have a peer dependency on react router ([#12437](https://github.com/remix-run/react-router/pull/12437))
1955- Generate wide `matches` and `params` types for current route and child routes ([#12397](https://github.com/remix-run/react-router/pull/12397))
1956
1957 At runtime, `matches` includes child route matches and `params` include child route path parameters.
1958 But previously, we only generated types for parent routes in `matches`; for `params`, we only considered the parent routes and the current route.
1959 To align our generated types more closely to the runtime behavior, we now generate more permissive, wider types when accessing child route information.
1960
1961## 7.0.1
1962
1963_No changes_
1964
1965## 7.0.0
1966
1967### Major Changes
1968
1969- Remove the original `defer` implementation in favor of using raw promises via single fetch and `turbo-stream`. This removes these exports from React Router: ([#11744](https://github.com/remix-run/react-router/pull/11744))
1970 - `defer`
1971 - `AbortedDeferredError`
1972 - `type TypedDeferredData`
1973 - `UNSAFE_DeferredData`
1974 - `UNSAFE_DEFERRED_SYMBOL`,
1975
1976- - Collapse `@remix-run/router` into `react-router` ([#11505](https://github.com/remix-run/react-router/pull/11505))
1977 - Collapse `react-router-dom` into `react-router`
1978 - Collapse `@remix-run/server-runtime` into `react-router`
1979 - Collapse `@remix-run/testing` into `react-router`
1980
1981- Remove single fetch future flag. ([#11522](https://github.com/remix-run/react-router/pull/11522))
1982
1983- Drop support for Node 16, React Router SSR now requires Node 18 or higher ([#11391](https://github.com/remix-run/react-router/pull/11391))
1984
1985- Remove `future.v7_startTransition` flag ([#11696](https://github.com/remix-run/react-router/pull/11696))
1986
1987- - Expose the underlying router promises from the following APIs for compsition in React 19 APIs: ([#11521](https://github.com/remix-run/react-router/pull/11521))
1988 - `useNavigate()`
1989 - `useSubmit`
1990 - `useFetcher().load`
1991 - `useFetcher().submit`
1992 - `useRevalidator.revalidate`
1993
1994- Remove `future.v7_normalizeFormMethod` future flag ([#11697](https://github.com/remix-run/react-router/pull/11697))
1995
1996- For Remix consumers migrating to React Router, the `crypto` global from the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) is now required when using cookie and session APIs. This means that the following APIs are provided from `react-router` rather than platform-specific packages: ([#11837](https://github.com/remix-run/react-router/pull/11837))
1997 - `createCookie`
1998 - `createCookieSessionStorage`
1999 - `createMemorySessionStorage`
2000 - `createSessionStorage`
2001
2002 For consumers running older versions of Node, the `installGlobals` function from `@remix-run/node` has been updated to define `globalThis.crypto`, using [Node's `require('node:crypto').webcrypto` implementation.](https://nodejs.org/api/webcrypto.html)
2003
2004 Since platform-specific packages no longer need to implement this API, the following low-level APIs have been removed:
2005 - `createCookieFactory`
2006 - `createSessionStorageFactory`
2007 - `createCookieSessionStorageFactory`
2008 - `createMemorySessionStorageFactory`
2009
2010- Imports/Exports cleanup ([#11840](https://github.com/remix-run/react-router/pull/11840))
2011 - Removed the following exports that were previously public API from `@remix-run/router`
2012 - types
2013 - `AgnosticDataIndexRouteObject`
2014 - `AgnosticDataNonIndexRouteObject`
2015 - `AgnosticDataRouteMatch`
2016 - `AgnosticDataRouteObject`
2017 - `AgnosticIndexRouteObject`
2018 - `AgnosticNonIndexRouteObject`
2019 - `AgnosticRouteMatch`
2020 - `AgnosticRouteObject`
2021 - `TrackedPromise`
2022 - `unstable_AgnosticPatchRoutesOnMissFunction`
2023 - `Action` -> exported as `NavigationType` via `react-router`
2024 - `Router` exported as `DataRouter` to differentiate from RR's `<Router>`
2025 - API
2026 - `getToPathname` (`@private`)
2027 - `joinPaths` (`@private`)
2028 - `normalizePathname` (`@private`)
2029 - `resolveTo` (`@private`)
2030 - `stripBasename` (`@private`)
2031 - `createBrowserHistory` -> in favor of `createBrowserRouter`
2032 - `createHashHistory` -> in favor of `createHashRouter`
2033 - `createMemoryHistory` -> in favor of `createMemoryRouter`
2034 - `createRouter`
2035 - `createStaticHandler` -> in favor of wrapper `createStaticHandler` in RR Dom
2036 - `getStaticContextFromError`
2037 - Removed the following exports that were previously public API from `react-router`
2038 - `Hash`
2039 - `Pathname`
2040 - `Search`
2041
2042- update minimum node version to 18 ([#11690](https://github.com/remix-run/react-router/pull/11690))
2043
2044- Remove `future.v7_prependBasename` from the ionternalized `@remix-run/router` package ([#11726](https://github.com/remix-run/react-router/pull/11726))
2045
2046- Migrate Remix type generics to React Router ([#12180](https://github.com/remix-run/react-router/pull/12180))
2047 - These generics are provided for Remix v2 migration purposes
2048 - These generics and the APIs they exist on should be considered informally deprecated in favor of the new `Route.*` types
2049 - Anyone migrating from React Router v6 should probably not leverage these new generics and should migrate straight to the `Route.*` types
2050 - For React Router v6 users, these generics are new and should not impact your app, with one exception
2051 - `useFetcher` previously had an optional generic (used primarily by Remix v2) that expected the data type
2052 - This has been updated in v7 to expect the type of the function that generates the data (i.e., `typeof loader`/`typeof action`)
2053 - Therefore, you should update your usages:
2054 - ❌ `useFetcher<LoaderData>()`
2055 - ✅ `useFetcher<typeof loader>()`
2056
2057- Remove `future.v7_throwAbortReason` from internalized `@remix-run/router` package ([#11728](https://github.com/remix-run/react-router/pull/11728))
2058
2059- Add `exports` field to all packages ([#11675](https://github.com/remix-run/react-router/pull/11675))
2060
2061- node package no longer re-exports from react-router ([#11702](https://github.com/remix-run/react-router/pull/11702))
2062
2063- renamed RemixContext to FrameworkContext ([#11705](https://github.com/remix-run/react-router/pull/11705))
2064
2065- updates the minimum React version to 18 ([#11689](https://github.com/remix-run/react-router/pull/11689))
2066
2067- PrefetchPageDescriptor replaced by PageLinkDescriptor ([#11960](https://github.com/remix-run/react-router/pull/11960))
2068
2069- - Consolidate types previously duplicated across `@remix-run/router`, `@remix-run/server-runtime`, and `@remix-run/react` now that they all live in `react-router` ([#12177](https://github.com/remix-run/react-router/pull/12177))
2070 - Examples: `LoaderFunction`, `LoaderFunctionArgs`, `ActionFunction`, `ActionFunctionArgs`, `DataFunctionArgs`, `RouteManifest`, `LinksFunction`, `Route`, `EntryRoute`
2071 - The `RouteManifest` type used by the "remix" code is now slightly stricter because it is using the former `@remix-run/router` `RouteManifest`
2072 - `Record<string, Route> -> Record<string, Route | undefined>`
2073 - Removed `AppData` type in favor of inlining `unknown` in the few locations it was used
2074 - Removed `ServerRuntimeMeta*` types in favor of the `Meta*` types they were duplicated from
2075
2076- - Remove the `future.v7_partialHydration` flag ([#11725](https://github.com/remix-run/react-router/pull/11725))
2077 - This also removes the `<RouterProvider fallbackElement>` prop
2078 - To migrate, move the `fallbackElement` to a `hydrateFallbackElement`/`HydrateFallback` on your root route
2079 - Also worth nothing there is a related breaking changer with this future flag:
2080 - Without `future.v7_partialHydration` (when using `fallbackElement`), `state.navigation` was populated during the initial load
2081 - With `future.v7_partialHydration`, `state.navigation` remains in an `"idle"` state during the initial load
2082
2083- Remove `v7_relativeSplatPath` future flag ([#11695](https://github.com/remix-run/react-router/pull/11695))
2084
2085- Drop support for Node 18, update minimum Node vestion to 20 ([#12171](https://github.com/remix-run/react-router/pull/12171))
2086 - Remove `installGlobals()` as this should no longer be necessary
2087
2088- Remove remaining future flags ([#11820](https://github.com/remix-run/react-router/pull/11820))
2089 - React Router `v7_skipActionErrorRevalidation`
2090 - Remix `v3_fetcherPersist`, `v3_relativeSplatPath`, `v3_throwAbortReason`
2091
2092- rename createRemixStub to createRoutesStub ([#11692](https://github.com/remix-run/react-router/pull/11692))
2093
2094- Remove `@remix-run/router` deprecated `detectErrorBoundary` option in favor of `mapRouteProperties` ([#11751](https://github.com/remix-run/react-router/pull/11751))
2095
2096- Add `react-router/dom` subpath export to properly enable `react-dom` as an optional `peerDependency` ([#11851](https://github.com/remix-run/react-router/pull/11851))
2097 - This ensures that we don't blindly `import ReactDOM from "react-dom"` in `<RouterProvider>` in order to access `ReactDOM.flushSync()`, since that would break `createMemoryRouter` use cases in non-DOM environments
2098 - DOM environments should import from `react-router/dom` to get the proper component that makes `ReactDOM.flushSync()` available:
2099 - If you are using the Vite plugin, use this in your `entry.client.tsx`:
2100 - `import { HydratedRouter } from 'react-router/dom'`
2101 - If you are not using the Vite plugin and are manually calling `createBrowserRouter`/`createHashRouter`:
2102 - `import { RouterProvider } from "react-router/dom"`
2103
2104- Remove `future.v7_fetcherPersist` flag ([#11731](https://github.com/remix-run/react-router/pull/11731))
2105
2106- Update `cookie` dependency to `^1.0.1` - please see the [release notes](https://github.com/jshttp/cookie/releases) for any breaking changes ([#12172](https://github.com/remix-run/react-router/pull/12172))
2107
2108### Minor Changes
2109
2110- - Add support for `prerender` config in the React Router vite plugin, to support existing SSG use-cases ([#11539](https://github.com/remix-run/react-router/pull/11539))
2111 - You can use the `prerender` config to pre-render your `.html` and `.data` files at build time and then serve them statically at runtime (either from a running server or a CDN)
2112 - `prerender` can either be an array of string paths, or a function (sync or async) that returns an array of strings so that you can dynamically generate the paths by talking to your CMS, etc.
2113
2114 ```ts
2115 // react-router.config.ts
2116 import type { Config } from "@react-router/dev/config";
2117
2118 export default {
2119 async prerender() {
2120 let slugs = await fakeGetSlugsFromCms();
2121 // Prerender these paths into `.html` files at build time, and `.data`
2122 // files if they have loaders
2123 return ["/", "/about", ...slugs.map((slug) => `/product/${slug}`)];
2124 },
2125 } satisfies Config;
2126
2127 async function fakeGetSlugsFromCms() {
2128 await new Promise((r) => setTimeout(r, 1000));
2129 return ["shirt", "hat"];
2130 }
2131 ```
2132
2133- Params, loader data, and action data as props for route component exports ([#11961](https://github.com/remix-run/react-router/pull/11961))
2134
2135 ```tsx
2136 export default function Component({ params, loaderData, actionData }) {}
2137
2138 export function HydrateFallback({ params }) {}
2139 export function ErrorBoundary({ params, loaderData, actionData }) {}
2140 ```
2141
2142- Remove duplicate `RouterProvider` impliementations ([#11679](https://github.com/remix-run/react-router/pull/11679))
2143
2144- ### Typesafety improvements ([#12019](https://github.com/remix-run/react-router/pull/12019))
2145
2146 React Router now generates types for each of your route modules.
2147 You can access those types by importing them from `./+types.<route filename without extension>`.
2148 For example:
2149
2150 ```ts
2151 // app/routes/product.tsx
2152 import type * as Route from "./+types.product";
2153
2154 export function loader({ params }: Route.LoaderArgs) {}
2155
2156 export default function Component({ loaderData }: Route.ComponentProps) {}
2157 ```
2158
2159 This initial implementation targets type inference for:
2160 - `Params` : Path parameters from your routing config in `routes.ts` including file-based routing
2161 - `LoaderData` : Loader data from `loader` and/or `clientLoader` within your route module
2162 - `ActionData` : Action data from `action` and/or `clientAction` within your route module
2163
2164 In the future, we plan to add types for the rest of the route module exports: `meta`, `links`, `headers`, `shouldRevalidate`, etc.
2165 We also plan to generate types for typesafe `Link`s:
2166
2167 ```tsx
2168 <Link to="/products/:id" params={{ id: 1 }} />
2169 // ^^^^^^^^^^^^^ ^^^^^^^^^
2170 // typesafe `to` and `params` based on the available routes in your app
2171 ```
2172
2173 Check out our docs for more:
2174 - [_Explanations > Type Safety_](https://reactrouter.com/dev/guides/explanation/type-safety)
2175 - [_How-To > Setting up type safety_](https://reactrouter.com/dev/guides/how-to/setting-up-type-safety)
2176
2177- Stabilize `unstable_dataStrategy` ([#11969](https://github.com/remix-run/react-router/pull/11969))
2178
2179- Stabilize `unstable_patchRoutesOnNavigation` ([#11970](https://github.com/remix-run/react-router/pull/11970))
2180
2181### Patch Changes
2182
2183- No changes ([`506329c4e`](https://github.com/remix-run/react-router/commit/506329c4e2e7aba9837cbfa44df6103b49423745))
2184
2185- chore: re-enable development warnings through a `development` exports condition. ([#12269](https://github.com/remix-run/react-router/pull/12269))
2186
2187- Remove unstable upload handler. ([#12015](https://github.com/remix-run/react-router/pull/12015))
2188
2189- Remove unneeded dependency on @web3-storage/multipart-parser ([#12274](https://github.com/remix-run/react-router/pull/12274))
2190
2191- Fix redirects returned from loaders/actions using `data()` ([#12021](https://github.com/remix-run/react-router/pull/12021))
2192
2193- fix(react-router): (v7) fix static prerender of non-ascii characters ([#12161](https://github.com/remix-run/react-router/pull/12161))
2194
2195- Replace `substr` with `substring` ([#12080](https://github.com/remix-run/react-router/pull/12080))
2196
2197- Remove the deprecated `json` utility ([#12146](https://github.com/remix-run/react-router/pull/12146))
2198 - You can use [`Response.json`](https://developer.mozilla.org/en-US/docs/Web/API/Response/json_static) if you still need to construct JSON responses in your app
2199
2200- Remove unneeded dependency on source-map ([#12275](https://github.com/remix-run/react-router/pull/12275))
2201
2202## 6.28.0
2203
2204### Minor Changes
2205
2206- - Log deprecation warnings for v7 flags ([#11750](https://github.com/remix-run/react-router/pull/11750))
2207 - Add deprecation warnings to `json`/`defer` in favor of returning raw objects
2208 - These methods will be removed in React Router v7
2209
2210### Patch Changes
2211
2212- Update JSDoc URLs for new website structure (add /v6/ segment) ([#12141](https://github.com/remix-run/react-router/pull/12141))
2213- Updated dependencies:
2214 - `@remix-run/router@1.21.0`
2215
2216## 6.27.0
2217
2218### Minor Changes
2219
2220- Stabilize `unstable_patchRoutesOnNavigation` ([#11973](https://github.com/remix-run/react-router/pull/11973))
2221 - Add new `PatchRoutesOnNavigationFunctionArgs` type for convenience ([#11967](https://github.com/remix-run/react-router/pull/11967))
2222- Stabilize `unstable_dataStrategy` ([#11974](https://github.com/remix-run/react-router/pull/11974))
2223- Stabilize the `unstable_flushSync` option for navigations and fetchers ([#11989](https://github.com/remix-run/react-router/pull/11989))
2224- Stabilize the `unstable_viewTransition` option for navigations and the corresponding `unstable_useViewTransitionState` hook ([#11989](https://github.com/remix-run/react-router/pull/11989))
2225
2226### Patch Changes
2227
2228- Fix bug when submitting to the current contextual route (parent route with an index child) when an `?index` param already exists from a prior submission ([#12003](https://github.com/remix-run/react-router/pull/12003))
2229
2230- Fix `useFormAction` bug - when removing `?index` param it would not keep other non-Remix `index` params ([#12003](https://github.com/remix-run/react-router/pull/12003))
2231
2232- Fix types for `RouteObject` within `PatchRoutesOnNavigationFunction`'s `patch` method so it doesn't expect agnostic route objects passed to `patch` ([#11967](https://github.com/remix-run/react-router/pull/11967))
2233
2234- Updated dependencies:
2235 - `@remix-run/router@1.20.0`
2236
2237## 6.26.2
2238
2239### Patch Changes
2240
2241- Updated dependencies:
2242 - `@remix-run/router@1.19.2`
2243
2244## 6.26.1
2245
2246### Patch Changes
2247
2248- Rename `unstable_patchRoutesOnMiss` to `unstable_patchRoutesOnNavigation` to match new behavior ([#11888](https://github.com/remix-run/react-router/pull/11888))
2249- Updated dependencies:
2250 - `@remix-run/router@1.19.1`
2251
2252## 6.26.0
2253
2254### Minor Changes
2255
2256- Add a new `replace(url, init?)` alternative to `redirect(url, init?)` that performs a `history.replaceState` instead of a `history.pushState` on client-side navigation redirects ([#11811](https://github.com/remix-run/react-router/pull/11811))
2257
2258### Patch Changes
2259
2260- Fix initial hydration behavior when using `future.v7_partialHydration` along with `unstable_patchRoutesOnMiss` ([#11838](https://github.com/remix-run/react-router/pull/11838))
2261 - During initial hydration, `router.state.matches` will now include any partial matches so that we can render ancestor `HydrateFallback` components
2262- Updated dependencies:
2263 - `@remix-run/router@1.19.0`
2264
2265## 6.25.1
2266
2267No significant changes to this package were made in this release. [See the repo `CHANGELOG.md`](https://github.com/remix-run/react-router/blob/main/CHANGELOG.md) for an overview of all changes in v6.25.1.
2268
2269## 6.25.0
2270
2271### Minor Changes
2272
2273- Stabilize `future.unstable_skipActionErrorRevalidation` as `future.v7_skipActionErrorRevalidation` ([#11769](https://github.com/remix-run/react-router/pull/11769))
2274 - When this flag is enabled, actions will not automatically trigger a revalidation if they return/throw a `Response` with a `4xx`/`5xx` status code
2275 - You may still opt-into revalidation via `shouldRevalidate`
2276 - This also changes `shouldRevalidate`'s `unstable_actionStatus` parameter to `actionStatus`
2277
2278### Patch Changes
2279
2280- Fix regression and properly decode paths inside `useMatch` so matches/params reflect decoded params ([#11789](https://github.com/remix-run/react-router/pull/11789))
2281- Updated dependencies:
2282 - `@remix-run/router@1.18.0`
2283
2284## 6.24.1
2285
2286### Patch Changes
2287
2288- When using `future.v7_relativeSplatPath`, properly resolve relative paths in splat routes that are children of pathless routes ([#11633](https://github.com/remix-run/react-router/pull/11633))
2289- Updated dependencies:
2290 - `@remix-run/router@1.17.1`
2291
2292## 6.24.0
2293
2294### Minor Changes
2295
2296- Add support for Lazy Route Discovery (a.k.a. Fog of War) ([#11626](https://github.com/remix-run/react-router/pull/11626))
2297 - RFC: <https://github.com/remix-run/react-router/discussions/11113>
2298 - `unstable_patchRoutesOnMiss` docs: <https://reactrouter.com/v6/routers/create-browser-router>
2299
2300### Patch Changes
2301
2302- Updated dependencies:
2303 - `@remix-run/router@1.17.0`
2304
2305## 6.23.1
2306
2307### Patch Changes
2308
2309- allow undefined to be resolved with `<Await>` ([#11513](https://github.com/remix-run/react-router/pull/11513))
2310- Updated dependencies:
2311 - `@remix-run/router@1.16.1`
2312
2313## 6.23.0
2314
2315### Minor Changes
2316
2317- Add a new `unstable_dataStrategy` configuration option ([#11098](https://github.com/remix-run/react-router/pull/11098))
2318 - This option allows Data Router applications to take control over the approach for executing route loaders and actions
2319 - The default implementation is today's behavior, to fetch all loaders in parallel, but this option allows users to implement more advanced data flows including Remix single-fetch, middleware/context APIs, automatic loader caching, and more
2320
2321### Patch Changes
2322
2323- Updated dependencies:
2324 - `@remix-run/router@1.16.0`
2325
2326## 6.22.3
2327
2328### Patch Changes
2329
2330- Updated dependencies:
2331 - `@remix-run/router@1.15.3`
2332
2333## 6.22.2
2334
2335### Patch Changes
2336
2337- Updated dependencies:
2338 - `@remix-run/router@1.15.2`
2339
2340## 6.22.1
2341
2342### Patch Changes
2343
2344- Fix encoding/decoding issues with pre-encoded dynamic parameter values ([#11199](https://github.com/remix-run/react-router/pull/11199))
2345- Updated dependencies:
2346 - `@remix-run/router@1.15.1`
2347
2348## 6.22.0
2349
2350### Patch Changes
2351
2352- Updated dependencies:
2353 - `@remix-run/router@1.15.0`
2354
2355## 6.21.3
2356
2357### Patch Changes
2358
2359- Remove leftover `unstable_` prefix from `Blocker`/`BlockerFunction` types ([#11187](https://github.com/remix-run/react-router/pull/11187))
2360
2361## 6.21.2
2362
2363### Patch Changes
2364
2365- Updated dependencies:
2366 - `@remix-run/router@1.14.2`
2367
2368## 6.21.1
2369
2370### Patch Changes
2371
2372- Fix bug with `route.lazy` not working correctly on initial SPA load when `v7_partialHydration` is specified ([#11121](https://github.com/remix-run/react-router/pull/11121))
2373- Updated dependencies:
2374 - `@remix-run/router@1.14.1`
2375
2376## 6.21.0
2377
2378### Minor Changes
2379
2380- Add a new `future.v7_relativeSplatPath` flag to implement a breaking bug fix to relative routing when inside a splat route. ([#11087](https://github.com/remix-run/react-router/pull/11087))
2381
2382 This fix was originally added in [#10983](https://github.com/remix-run/react-router/issues/10983) and was later reverted in [#11078](https://github.com/remix-run/react-router/pull/11078) because it was determined that a large number of existing applications were relying on the buggy behavior (see [#11052](https://github.com/remix-run/react-router/issues/11052))
2383
2384 **The Bug**
2385 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.
2386
2387 **The Background**
2388 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:
2389
2390 ```jsx
2391 <BrowserRouter>
2392 <Routes>
2393 <Route path="/" element={<Home />} />
2394 <Route path="dashboard/*" element={<Dashboard />} />
2395 </Routes>
2396 </BrowserRouter>
2397 ```
2398
2399 Any paths like `/dashboard`, `/dashboard/team`, `/dashboard/projects` will match the `Dashboard` route. The dashboard component itself can then render nested `<Routes>`:
2400
2401 ```jsx
2402 function Dashboard() {
2403 return (
2404 <div>
2405 <h2>Dashboard</h2>
2406 <nav>
2407 <Link to="/">Dashboard Home</Link>
2408 <Link to="team">Team</Link>
2409 <Link to="projects">Projects</Link>
2410 </nav>
2411
2412 <Routes>
2413 <Route path="/" element={<DashboardHome />} />
2414 <Route path="team" element={<DashboardTeam />} />
2415 <Route path="projects" element={<DashboardProjects />} />
2416 </Routes>
2417 </div>
2418 );
2419 }
2420 ```
2421
2422 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.
2423
2424 **The Problem**
2425
2426 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 `"."`:
2427
2428 ```jsx
2429 // If we are on URL /dashboard/team, and we want to link to /dashboard/team:
2430 function DashboardTeam() {
2431 // ❌ This is broken and results in <a href="/dashboard">
2432 return <Link to=".">A broken link to the Current URL</Link>;
2433
2434 // ✅ This is fixed but super unintuitive since we're already at /dashboard/team!
2435 return <Link to="./team">A broken link to the Current URL</Link>;
2436 }
2437 ```
2438
2439 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.
2440
2441 Even worse, consider a nested splat route configuration:
2442
2443 ```jsx
2444 <BrowserRouter>
2445 <Routes>
2446 <Route path="dashboard">
2447 <Route path="*" element={<Dashboard />} />
2448 </Route>
2449 </Routes>
2450 </BrowserRouter>
2451 ```
2452
2453 Now, a `<Link to=".">` and a `<Link to="..">` inside the `Dashboard` component go to the same place! That is definitely not correct!
2454
2455 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:
2456
2457 ```jsx
2458 let router = createBrowserRouter({
2459 path: "/dashboard",
2460 children: [
2461 {
2462 path: "*",
2463 action: dashboardAction,
2464 Component() {
2465 // ❌ This form is broken! It throws a 405 error when it submits because
2466 // it tries to submit to /dashboard (without the splat value) and the parent
2467 // `/dashboard` route doesn't have an action
2468 return <Form method="post">...</Form>;
2469 },
2470 },
2471 ],
2472 });
2473 ```
2474
2475 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.
2476
2477 **The Solution**
2478 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:
2479
2480 ```jsx
2481 <BrowserRouter>
2482 <Routes>
2483 <Route path="dashboard">
2484 <Route index path="*" element={<Dashboard />} />
2485 </Route>
2486 </Routes>
2487 </BrowserRouter>
2488
2489 function Dashboard() {
2490 return (
2491 <div>
2492 <h2>Dashboard</h2>
2493 <nav>
2494 <Link to="..">Dashboard Home</Link>
2495 <Link to="../team">Team</Link>
2496 <Link to="../projects">Projects</Link>
2497 </nav>
2498
2499 <Routes>
2500 <Route path="/" element={<DashboardHome />} />
2501 <Route path="team" element={<DashboardTeam />} />
2502 <Route path="projects" element={<DashboardProjects />} />
2503 </Router>
2504 </div>
2505 );
2506 }
2507 ```
2508
2509 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".
2510
2511### Patch Changes
2512
2513- Properly handle falsy error values in ErrorBoundary's ([#11071](https://github.com/remix-run/react-router/pull/11071))
2514- Updated dependencies:
2515 - `@remix-run/router@1.14.0`
2516
2517## 6.20.1
2518
2519### Patch Changes
2520
2521- Revert the `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](https://github.com/remix-run/react-router/pull/11078))
2522- Updated dependencies:
2523 - `@remix-run/router@1.13.1`
2524
2525## 6.20.0
2526
2527### Minor Changes
2528
2529- Export the `PathParam` type from the public API ([#10719](https://github.com/remix-run/react-router/pull/10719))
2530
2531### Patch Changes
2532
2533- Fix bug with `resolveTo` in splat routes ([#11045](https://github.com/remix-run/react-router/pull/11045))
2534 - This is a follow up to [#10983](https://github.com/remix-run/react-router/pull/10983) to handle the few other code paths using `getPathContributingMatches`
2535 - This removes the `UNSAFE_getPathContributingMatches` export from `@remix-run/router` since we no longer need this in the `react-router`/`react-router-dom` layers
2536- Updated dependencies:
2537 - `@remix-run/router@1.13.0`
2538
2539## 6.19.0
2540
2541### Minor Changes
2542
2543- Add `unstable_flushSync` option to `useNavigate`/`useSumbit`/`fetcher.load`/`fetcher.submit` to opt-out of `React.startTransition` and into `ReactDOM.flushSync` for state updates ([#11005](https://github.com/remix-run/react-router/pull/11005))
2544- Remove the `unstable_` prefix from the [`useBlocker`](https://reactrouter.com/v6/hooks/use-blocker) 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](https://github.com/remix-run/react-router/pull/10991))
2545
2546### Patch Changes
2547
2548- Fix `useActionData` so it returns proper contextual action data and not _any_ action data in the tree ([#11023](https://github.com/remix-run/react-router/pull/11023))
2549
2550- Fix bug in `useResolvedPath` that would cause `useResolvedPath(".")` in a splat route to lose the splat portion of the URL path. ([#10983](https://github.com/remix-run/react-router/pull/10983))
2551 - ⚠️ This fixes a quite long-standing bug specifically for `"."` 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.
2552
2553- Updated dependencies:
2554 - `@remix-run/router@1.12.0`
2555
2556## 6.18.0
2557
2558### Patch Changes
2559
2560- Fix the `future` prop on `BrowserRouter`, `HashRouter` and `MemoryRouter` so that it accepts a `Partial<FutureConfig>` instead of requiring all flags to be included. ([#10962](https://github.com/remix-run/react-router/pull/10962))
2561- Updated dependencies:
2562 - `@remix-run/router@1.11.0`
2563
2564## 6.17.0
2565
2566### Patch Changes
2567
2568- Fix `RouterProvider` `future` prop type to be a `Partial<FutureConfig>` so that not all flags must be specified ([#10900](https://github.com/remix-run/react-router/pull/10900))
2569- Updated dependencies:
2570 - `@remix-run/router@1.10.0`
2571
2572## 6.16.0
2573
2574### Minor Changes
2575
2576- In order to move towards stricter TypeScript support in the future, we're aiming to replace current usages of `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](https://github.com/remix-run/react-router/pull/10843))
2577 - `Location` now accepts a generic for the `location.state` value
2578 - `ActionFunctionArgs`/`ActionFunction`/`LoaderFunctionArgs`/`LoaderFunction` now accept a generic for the `context` parameter (only used in SSR usages via `createStaticHandler`)
2579 - The return type of `useMatches` (now exported as `UIMatch`) accepts generics for `match.data` and `match.handle` - both of which were already set to `unknown`
2580- Move the `@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](https://github.com/remix-run/react-router/pull/10811))
2581- Export `ShouldRevalidateFunctionArgs` interface ([#10797](https://github.com/remix-run/react-router/pull/10797))
2582- Removed private/internal APIs only required for the Remix v1 backwards compatibility layer and no longer needed in Remix v2 (`_isFetchActionRedirect`, `_hasFetcherDoneAnything`) ([#10715](https://github.com/remix-run/react-router/pull/10715))
2583
2584### Patch Changes
2585
2586- Updated dependencies:
2587 - `@remix-run/router@1.9.0`
2588
2589## 6.15.0
2590
2591### Minor Changes
2592
2593- Add's a new `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](https://github.com/remix-run/react-router/pull/10705))
2594
2595### Patch Changes
2596
2597- Ensure `useRevalidator` is referentially stable across re-renders if revalidations are not actively occurring ([#10707](https://github.com/remix-run/react-router/pull/10707))
2598- Updated dependencies:
2599 - `@remix-run/router@1.8.0`
2600
2601## 6.14.2
2602
2603### Patch Changes
2604
2605- Updated dependencies:
2606 - `@remix-run/router@1.7.2`
2607
2608## 6.14.1
2609
2610### Patch Changes
2611
2612- Fix loop in `unstable_useBlocker` when used with an unstable blocker function ([#10652](https://github.com/remix-run/react-router/pull/10652))
2613- Fix issues with reused blockers on subsequent navigations ([#10656](https://github.com/remix-run/react-router/pull/10656))
2614- Updated dependencies:
2615 - `@remix-run/router@1.7.1`
2616
2617## 6.14.0
2618
2619### Patch Changes
2620
2621- Strip `basename` from locations provided to `unstable_useBlocker` functions to match `useLocation` ([#10573](https://github.com/remix-run/react-router/pull/10573))
2622- Fix `generatePath` when passed a numeric `0` value parameter ([#10612](https://github.com/remix-run/react-router/pull/10612))
2623- Fix `unstable_useBlocker` key issues in `StrictMode` ([#10573](https://github.com/remix-run/react-router/pull/10573))
2624- Fix `tsc --skipLibCheck:false` issues on React 17 ([#10622](https://github.com/remix-run/react-router/pull/10622))
2625- Upgrade `typescript` to 5.1 ([#10581](https://github.com/remix-run/react-router/pull/10581))
2626- Updated dependencies:
2627 - `@remix-run/router@1.7.0`
2628
2629## 6.13.0
2630
2631### Minor Changes
2632
2633- Move [`React.startTransition`](https://react.dev/reference/react/startTransition) usage behind a [future flag](https://reactrouter.com/v6/guides/api-development-strategy) 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](https://github.com/remix-run/react-router/pull/10596))
2634
2635 Existing behavior will no longer include `React.startTransition`:
2636
2637 ```jsx
2638 <BrowserRouter>
2639 <Routes>{/*...*/}</Routes>
2640 </BrowserRouter>
2641
2642 <RouterProvider router={router} />
2643 ```
2644
2645 If you wish to enable `React.startTransition`, pass the future flag to your component:
2646
2647 ```jsx
2648 <BrowserRouter future={{ v7_startTransition: true }}>
2649 <Routes>{/*...*/}</Routes>
2650 </BrowserRouter>
2651
2652 <RouterProvider router={router} future={{ v7_startTransition: true }}/>
2653 ```
2654
2655### Patch Changes
2656
2657- Work around webpack/terser `React.startTransition` minification bug in production mode ([#10588](https://github.com/remix-run/react-router/pull/10588))
2658
2659## 6.12.1
2660
2661> \[!WARNING]
2662> Please use version `6.13.0` or later instead of `6.12.1`. This version suffers from a `webpack`/`terser` minification issue resulting in invalid minified code in your resulting production bundles which can cause issues in your application. See [#10579](https://github.com/remix-run/react-router/issues/10579) for more details.
2663
2664### Patch Changes
2665
2666- Adjust feature detection of `React.startTransition` to fix webpack + react 17 compilation error ([#10569](https://github.com/remix-run/react-router/pull/10569))
2667
2668## 6.12.0
2669
2670### Minor Changes
2671
2672- Wrap internal router state updates with `React.startTransition` if it exists ([#10438](https://github.com/remix-run/react-router/pull/10438))
2673
2674### Patch Changes
2675
2676- Updated dependencies:
2677 - `@remix-run/router@1.6.3`
2678
2679## 6.11.2
2680
2681### Patch Changes
2682
2683- Fix `basename` duplication in descendant `<Routes>` inside a `<RouterProvider>` ([#10492](https://github.com/remix-run/react-router/pull/10492))
2684- Updated dependencies:
2685 - `@remix-run/router@1.6.2`
2686
2687## 6.11.1
2688
2689### Patch Changes
2690
2691- Fix usage of `Component` API within descendant `<Routes>` ([#10434](https://github.com/remix-run/react-router/pull/10434))
2692- Fix bug when calling `useNavigate` from `<Routes>` inside a `<RouterProvider>` ([#10432](https://github.com/remix-run/react-router/pull/10432))
2693- Fix usage of `<Navigate>` in strict mode when using a data router ([#10435](https://github.com/remix-run/react-router/pull/10435))
2694- Updated dependencies:
2695 - `@remix-run/router@1.6.1`
2696
2697## 6.11.0
2698
2699### Patch Changes
2700
2701- Log loader/action errors to the console in dev for easier stack trace evaluation ([#10286](https://github.com/remix-run/react-router/pull/10286))
2702- Fix bug preventing rendering of descendant `<Routes>` when `RouterProvider` errors existed ([#10374](https://github.com/remix-run/react-router/pull/10374))
2703- Fix inadvertent re-renders when using `Component` instead of `element` on a route definition ([#10287](https://github.com/remix-run/react-router/pull/10287))
2704- Fix detection of `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](https://github.com/remix-run/react-router/pull/10394))
2705- Switched from `useSyncExternalStore` to `useState` for internal `@remix-run/router` router state syncing in `<RouterProvider>`. We found some [subtle bugs](https://codesandbox.io/s/use-sync-external-store-loop-9g7b81) where router state updates got propagated _before_ other normal `useState` updates, which could lead to footguns in `useEffect` calls. ([#10377](https://github.com/remix-run/react-router/pull/10377), [#10409](https://github.com/remix-run/react-router/pull/10409))
2706- Allow `useRevalidator()` to resolve a loader-driven error boundary scenario ([#10369](https://github.com/remix-run/react-router/pull/10369))
2707- Avoid unnecessary unsubscribe/resubscribes on router state changes ([#10409](https://github.com/remix-run/react-router/pull/10409))
2708- When using a `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](https://github.com/remix-run/react-router/pull/10336))
2709- Updated dependencies:
2710 - `@remix-run/router@1.6.0`
2711
2712## 6.10.0
2713
2714### Minor Changes
2715
2716- Added support for [**Future Flags**](https://reactrouter.com/v6/guides/api-development-strategy) in React Router. The first 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()` behavior. ([#10207](https://github.com/remix-run/react-router/pull/10207))
2717 - When `future.v7_normalizeFormMethod === false` (default v6 behavior),
2718 - `useNavigation().formMethod` is lowercase
2719 - `useFetcher().formMethod` is lowercase
2720 - When `future.v7_normalizeFormMethod === true`:
2721 - `useNavigation().formMethod` is uppercase
2722 - `useFetcher().formMethod` is uppercase
2723
2724### Patch Changes
2725
2726- Fix route ID generation when using Fragments in `createRoutesFromElements` ([#10193](https://github.com/remix-run/react-router/pull/10193))
2727- Updated dependencies:
2728 - `@remix-run/router@1.5.0`
2729
2730## 6.9.0
2731
2732### Minor Changes
2733
2734- React Router now supports an alternative way to define your route `element` and `errorElement` fields as React Components instead of React Elements. You can instead pass a React Component to the new `Component` and `ErrorBoundary` fields if you choose. There is no functional difference between the two, so use whichever approach you prefer 😀. You shouldn't be defining both, but if you do `Component`/`ErrorBoundary` will "win". ([#10045](https://github.com/remix-run/react-router/pull/10045))
2735
2736 **Example JSON Syntax**
2737
2738 ```jsx
2739 // Both of these work the same:
2740 const elementRoutes = [{
2741 path: '/',
2742 element: <Home />,
2743 errorElement: <HomeError />,
2744 }]
2745
2746 const componentRoutes = [{
2747 path: '/',
2748 Component: Home,
2749 ErrorBoundary: HomeError,
2750 }]
2751
2752 function Home() { ... }
2753 function HomeError() { ... }
2754 ```
2755
2756 **Example JSX Syntax**
2757
2758 ```jsx
2759 // Both of these work the same:
2760 const elementRoutes = createRoutesFromElements(
2761 <Route path='/' element={<Home />} errorElement={<HomeError /> } />
2762 );
2763
2764 const componentRoutes = createRoutesFromElements(
2765 <Route path='/' Component={Home} ErrorBoundary={HomeError} />
2766 );
2767
2768 function Home() { ... }
2769 function HomeError() { ... }
2770 ```
2771
2772- **Introducing Lazy Route Modules!** ([#10045](https://github.com/remix-run/react-router/pull/10045))
2773
2774 In order to keep your application bundles small and support code-splitting of your routes, we've introduced a new `lazy()` route property. This is an async function that resolves the non-route-matching portions of your route definition (`loader`, `action`, `element`/`Component`, `errorElement`/`ErrorBoundary`, `shouldRevalidate`, `handle`).
2775
2776 Lazy routes are resolved on initial load and during the `loading` or `submitting` phase of a navigation or fetcher call. You cannot lazily define route-matching properties (`path`, `index`, `children`) since we only execute your lazy route functions after we've matched known routes.
2777
2778 Your `lazy` functions will typically return the result of a dynamic import.
2779
2780 ```jsx
2781 // In this example, we assume most folks land on the homepage so we include that
2782 // in our critical-path bundle, but then we lazily load modules for /a and /b so
2783 // they don't load until the user navigates to those routes
2784 let routes = createRoutesFromElements(
2785 <Route path="/" element={<Layout />}>
2786 <Route index element={<Home />} />
2787 <Route path="a" lazy={() => import("./a")} />
2788 <Route path="b" lazy={() => import("./b")} />
2789 </Route>,
2790 );
2791 ```
2792
2793 Then in your lazy route modules, export the properties you want defined for the route:
2794
2795 ```jsx
2796 export async function loader({ request }) {
2797 let data = await fetchData(request);
2798 return json(data);
2799 }
2800
2801 // Export a `Component` directly instead of needing to create a React Element from it
2802 export function Component() {
2803 let data = useLoaderData();
2804
2805 return (
2806 <>
2807 <h1>You made it!</h1>
2808 <p>{data}</p>
2809 </>
2810 );
2811 }
2812
2813 // Export an `ErrorBoundary` directly instead of needing to create a React Element from it
2814 export function ErrorBoundary() {
2815 let error = useRouteError();
2816 return isRouteErrorResponse(error) ? (
2817 <h1>
2818 {error.status} {error.statusText}
2819 </h1>
2820 ) : (
2821 <h1>{error.message || error}</h1>
2822 );
2823 }
2824 ```
2825
2826 An example of this in action can be found in the [`examples/lazy-loading-router-provider`](https://github.com/remix-run/react-router/tree/main/examples/lazy-loading-router-provider) directory of the repository.
2827
2828 🙌 Huge thanks to @rossipedia for the [Initial Proposal](https://github.com/remix-run/react-router/discussions/9826) and [POC Implementation](https://github.com/remix-run/react-router/pull/9830).
2829
2830- Updated dependencies:
2831 - `@remix-run/router@1.4.0`
2832
2833### Patch Changes
2834
2835- Fix `generatePath` incorrectly applying parameters in some cases ([#10078](https://github.com/remix-run/react-router/pull/10078))
2836- Improve memoization for context providers to avoid unnecessary re-renders ([#9983](https://github.com/remix-run/react-router/pull/9983))
2837
2838## 6.8.2
2839
2840### Patch Changes
2841
2842- Updated dependencies:
2843 - `@remix-run/router@1.3.3`
2844
2845## 6.8.1
2846
2847### Patch Changes
2848
2849- Remove inaccurate console warning for POP navigations and update active blocker logic ([#10030](https://github.com/remix-run/react-router/pull/10030))
2850- Updated dependencies:
2851 - `@remix-run/router@1.3.2`
2852
2853## 6.8.0
2854
2855### Patch Changes
2856
2857- Updated dependencies:
2858 - `@remix-run/router@1.3.1`
2859
2860## 6.7.0
2861
2862### Minor Changes
2863
2864- Add `unstable_useBlocker` hook for blocking navigations within the app's location origin ([#9709](https://github.com/remix-run/react-router/pull/9709))
2865
2866### Patch Changes
2867
2868- Fix `generatePath` when optional params are present ([#9764](https://github.com/remix-run/react-router/pull/9764))
2869- Update `<Await>` to accept `ReactNode` as children function return result ([#9896](https://github.com/remix-run/react-router/pull/9896))
2870- Updated dependencies:
2871 - `@remix-run/router@1.3.0`
2872
2873## 6.6.2
2874
2875### Patch Changes
2876
2877- Ensure `useId` consistency during SSR ([#9805](https://github.com/remix-run/react-router/pull/9805))
2878
2879## 6.6.1
2880
2881### Patch Changes
2882
2883- Updated dependencies:
2884 - `@remix-run/router@1.2.1`
2885
2886## 6.6.0
2887
2888### Patch Changes
2889
2890- Prevent `useLoaderData` usage in `errorElement` ([#9735](https://github.com/remix-run/react-router/pull/9735))
2891- Updated dependencies:
2892 - `@remix-run/router@1.2.0`
2893
2894## 6.5.0
2895
2896This release introduces support for [Optional Route Segments](https://github.com/remix-run/react-router/issues/9546). Now, adding a `?` to the end of any path segment will make that entire segment optional. This works for both static segments and dynamic parameters.
2897
2898**Optional Params Examples**
2899
2900- `<Route path=":lang?/about>` will match:
2901 - `/:lang/about`
2902 - `/about`
2903- `<Route path="/multistep/:widget1?/widget2?/widget3?">` will match:
2904 - `/multistep`
2905 - `/multistep/:widget1`
2906 - `/multistep/:widget1/:widget2`
2907 - `/multistep/:widget1/:widget2/:widget3`
2908
2909**Optional Static Segment Example**
2910
2911- `<Route path="/home?">` will match:
2912 - `/`
2913 - `/home`
2914- `<Route path="/fr?/about">` will match:
2915 - `/about`
2916 - `/fr/about`
2917
2918### Minor Changes
2919
2920- Allows optional routes and optional static segments ([#9650](https://github.com/remix-run/react-router/pull/9650))
2921
2922### Patch Changes
2923
2924- Stop incorrectly matching on partial named parameters, i.e. `<Route path="prefix-:param">`, to align with how splat parameters work. If you were previously relying on this behavior then it's recommended to extract the static portion of the path at the `useParams` call site: ([#9506](https://github.com/remix-run/react-router/pull/9506))
2925
2926```jsx
2927// Old behavior at URL /prefix-123
2928<Route path="prefix-:id" element={<Comp /> }>
2929
2930function Comp() {
2931 let params = useParams(); // { id: '123' }
2932 let id = params.id; // "123"
2933 ...
2934}
2935
2936// New behavior at URL /prefix-123
2937<Route path=":id" element={<Comp /> }>
2938
2939function Comp() {
2940 let params = useParams(); // { id: 'prefix-123' }
2941 let id = params.id.replace(/^prefix-/, ''); // "123"
2942 ...
2943}
2944```
2945
2946- Updated dependencies:
2947 - `@remix-run/router@1.1.0`
2948
2949## 6.4.5
2950
2951### Patch Changes
2952
2953- Updated dependencies:
2954 - `@remix-run/router@1.0.5`
2955
2956## 6.4.4
2957
2958### Patch Changes
2959
2960- Updated dependencies:
2961 - `@remix-run/router@1.0.4`
2962
2963## 6.4.3
2964
2965### Patch Changes
2966
2967- `useRoutes` should be able to return `null` when passing `locationArg` ([#9485](https://github.com/remix-run/react-router/pull/9485))
2968- fix `initialEntries` type in `createMemoryRouter` ([#9498](https://github.com/remix-run/react-router/pull/9498))
2969- Updated dependencies:
2970 - `@remix-run/router@1.0.3`
2971
2972## 6.4.2
2973
2974### Patch Changes
2975
2976- Fix `IndexRouteObject` and `NonIndexRouteObject` types to make `hasErrorElement` optional ([#9394](https://github.com/remix-run/react-router/pull/9394))
2977- Enhance console error messages for invalid usage of data router hooks ([#9311](https://github.com/remix-run/react-router/pull/9311))
2978- If an index route has children, it will result in a runtime error. We have strengthened our `RouteObject`/`RouteProps` types to surface the error in TypeScript. ([#9366](https://github.com/remix-run/react-router/pull/9366))
2979- Updated dependencies:
2980 - `@remix-run/router@1.0.2`
2981
2982## 6.4.1
2983
2984### Patch Changes
2985
2986- Preserve state from `initialEntries` ([#9288](https://github.com/remix-run/react-router/pull/9288))
2987- Updated dependencies:
2988 - `@remix-run/router@1.0.1`
2989
2990## 6.4.0
2991
2992Whoa this is a big one! `6.4.0` brings all the data loading and mutation APIs over from Remix. Here's a quick high level overview, but it's recommended you go check out the [docs](https://reactrouter.com), especially the [feature overview](https://reactrouter.com/en/6.4.0/start/overview) and the [tutorial](https://reactrouter.com/en/6.4.0/start/tutorial).
2993
2994**New APIs**
2995
2996- Create your router with `createMemoryRouter`
2997- Render your router with `<RouterProvider>`
2998- Load data with a Route `loader` and mutate with a Route `action`
2999- Handle errors with Route `errorElement`
3000- Defer non-critical data with `defer` and `Await`
3001
3002**Bug Fixes**
3003
3004- Path resolution is now trailing slash agnostic (#8861)
3005- `useLocation` returns the scoped location inside a `<Routes location>` component (#9094)
3006
3007**Updated Dependencies**
3008
3009- `@remix-run/router@1.0.0`