UNPKG

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