UNPKG

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