UNPKG

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