UNPKG

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