UNPKG

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