UNPKG

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