UNPKG

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