UNPKG

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