INDIE UNPKG

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