UNPKG

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