UNPKG

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