UNPKG

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