UNPKG

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