UNPKG

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