UNPKG

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