UNPKG

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