UNPKG

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