UNPKG

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