UNPKG

67.5 kBMarkdownView Raw
1# `react-router`
2
3## 7.4.0
4
5### Patch Changes
6
7- Fix root loader data on initial load redirects in SPA mode ([#13222](https://github.com/remix-run/react-router/pull/13222))
8- 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))
9- Fix `shouldRevalidate` behavior for `clientLoader`-only routes in `ssr:true` apps ([#13221](https://github.com/remix-run/react-router/pull/13221))
10- UNSTABLE: Fix `RequestHandler` `loadContext` parameter type when middleware is enabled ([#13204](https://github.com/remix-run/react-router/pull/13204))
11- 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))
12- 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))
13
14## 7.3.0
15
16### Minor Changes
17
18- Add `fetcherKey` as a parameter to `patchRoutesOnNavigation` ([#13061](https://github.com/remix-run/react-router/pull/13061))
19
20 - In framework mode, Lazy Route Discovery will now detect manifest version mismatches after a new deploy
21 - On navigations to undiscovered routes, this mismatch will trigger a document reload of the destination path
22 - On `fetcher` calls to undiscovered routes, this mismatch will trigger a document reload of the current path
23
24### Patch Changes
25
26- Skip resource route flow in dev server in SPA mode ([#13113](https://github.com/remix-run/react-router/pull/13113))
27
28- Support middleware on routes (unstable) ([#12941](https://github.com/remix-run/react-router/pull/12941))
29
30 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:
31
32 ```ts
33 import type { Config } from "@react-router/dev/config";
34 import type { Future } from "react-router";
35
36 declare module "react-router" {
37 interface Future {
38 unstable_middleware: true; // 👈 Enable middleware types
39 }
40 }
41
42 export default {
43 future: {
44 unstable_middleware: true, // 👈 Enable middleware
45 },
46 } satisfies Config;
47 ```
48
49 ⚠️ 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.
50
51 ⚠️ Enabling middleware contains a breaking change to the `context` parameter passed to your `loader`/`action` functions - see below for more information.
52
53 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.
54
55 ```tsx
56 // Framework mode
57 export const unstable_middleware = [serverLogger, serverAuth]; // server
58 export const unstable_clientMiddleware = [clientLogger]; // client
59
60 // Library mode
61 const routes = [
62 {
63 path: "/",
64 // Middlewares are client-side for library mode SPA's
65 unstable_middleware: [clientLogger, clientAuth],
66 loader: rootLoader,
67 Component: Root,
68 },
69 ];
70 ```
71
72 Here's a simple example of a client-side logging middleware that can be placed on the root route:
73
74 ```tsx
75 const clientLogger: Route.unstable_ClientMiddlewareFunction = async (
76 { request },
77 next
78 ) => {
79 let start = performance.now();
80
81 // Run the remaining middlewares and all route loaders
82 await next();
83
84 let duration = performance.now() - start;
85 console.log(`Navigated to ${request.url} (${duration}ms)`);
86 };
87 ```
88
89 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`.
90
91 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()`.
92
93 ```tsx
94 const serverLogger: Route.unstable_MiddlewareFunction = async (
95 { request, params, context },
96 next
97 ) => {
98 let start = performance.now();
99
100 // 👇 Grab the response here
101 let res = await next();
102
103 let duration = performance.now() - start;
104 console.log(`Navigated to ${request.url} (${duration}ms)`);
105
106 // 👇 And return it here (optional if you don't modify the response)
107 return res;
108 };
109 ```
110
111 You can throw a `redirect` from a middleware to short circuit any remaining processing:
112
113 ```tsx
114 import { sessionContext } from "../context";
115 const serverAuth: Route.unstable_MiddlewareFunction = (
116 { request, params, context },
117 next
118 ) => {
119 let session = context.get(sessionContext);
120 let user = session.get("user");
121 if (!user) {
122 session.set("returnTo", request.url);
123 throw redirect("/login", 302);
124 }
125 };
126 ```
127
128 _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`._
129
130 Here's another example of using a server middleware to detect 404s and check the CMS for a redirect:
131
132 ```tsx
133 const redirects: Route.unstable_MiddlewareFunction = async ({
134 request,
135 next,
136 }) => {
137 // attempt to handle the request
138 let res = await next();
139
140 // if it's a 404, check the CMS for a redirect, do it last
141 // because it's expensive
142 if (res.status === 404) {
143 let cmsRedirect = await checkCMSRedirects(request.url);
144 if (cmsRedirect) {
145 throw redirect(cmsRedirect, 302);
146 }
147 }
148
149 return res;
150 };
151 ```
152
153 **`context` parameter**
154
155 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`):
156
157 ```ts
158 import { unstable_createContext } from "react-router";
159 import { Route } from "./+types/root";
160 import type { Session } from "./sessions.server";
161 import { getSession } from "./sessions.server";
162
163 let sessionContext = unstable_createContext<Session>();
164
165 const sessionMiddleware: Route.unstable_MiddlewareFunction = ({
166 context,
167 request,
168 }) => {
169 let session = await getSession(request);
170 context.set(sessionContext, session);
171 // ^ must be of type Session
172 };
173
174 // ... then in some downstream middleware
175 const loggerMiddleware: Route.unstable_MiddlewareFunction = ({
176 context,
177 request,
178 }) => {
179 let session = context.get(sessionContext);
180 // ^ typeof Session
181 console.log(session.get("userId"), request.method, request.url);
182 };
183
184 // ... or some downstream loader
185 export function loader({ context }: Route.LoaderArgs) {
186 let session = context.get(sessionContext);
187 let profile = await getProfile(session.get("userId"));
188 return { profile };
189 }
190 ```
191
192 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>`):
193
194 ```ts
195 let adapterContext = unstable_createContext<MyAdapterContext>();
196
197 function getLoadContext(req, res): unstable_InitialContext {
198 let map = new Map();
199 map.set(adapterContext, getAdapterContext(req));
200 return map;
201 }
202 ```
203
204- Fix types for loaderData and actionData that contained `Record`s ([#13139](https://github.com/remix-run/react-router/pull/13139))
205
206 UNSTABLE(BREAKING):
207
208 `unstable_SerializesTo` added a way to register custom serialization types in Single Fetch for other library and framework authors like Apollo.
209 It was implemented with branded type whose branded property that was made optional so that casting arbitrary values was easy:
210
211 ```ts
212 // without the brand being marked as optional
213 let x1 = 42 as unknown as unstable_SerializesTo<number>;
214 // ^^^^^^^^^^
215
216 // with the brand being marked as optional
217 let x2 = 42 as unstable_SerializesTo<number>;
218 ```
219
220 However, this broke type inference in `loaderData` and `actionData` for any `Record` types as those would now (incorrectly) match `unstable_SerializesTo`.
221 This affected all users, not just those that depended on `unstable_SerializesTo`.
222 To fix this, the branded property of `unstable_SerializesTo` is marked as required instead of optional.
223
224 For library and framework authors using `unstable_SerializesTo`, you may need to add `as unknown` casts before casting to `unstable_SerializesTo`.
225
226- \[REMOVE] Remove middleware depth logic and always call middlware for all matches ([#13172](https://github.com/remix-run/react-router/pull/13172))
227
228- Fix single fetch `_root.data` requests when a `basename` is used ([#12898](https://github.com/remix-run/react-router/pull/12898))
229
230- Add `context` support to client side data routers (unstable) ([#12941](https://github.com/remix-run/react-router/pull/12941))
231
232 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:
233
234 ```ts
235 import { unstable_createContext } from "react-router";
236
237 type User = {
238 /*...*/
239 };
240
241 let userContext = unstable_createContext<User>();
242
243 function sessionMiddleware({ context }) {
244 let user = await getUser();
245 context.set(userContext, user);
246 }
247
248 // ... then in some downstream loader
249 function loader({ context }) {
250 let user = context.get(userContext);
251 let profile = await getProfile(user.id);
252 return { profile };
253 }
254 ```
255
256 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:
257
258 - Library mode - `createBrowserRouter(routes, { unstable_getContext })`
259 - Framework mode - `<HydratedRouter unstable_getContext>`
260
261 This function should return an value of type `unstable_InitialContext` which is a `Map<unstable_RouterContext, unknown>` of context's and initial values:
262
263 ```ts
264 const loggerContext = unstable_createContext<(...args: unknown[]) => void>();
265
266 function logger(...args: unknown[]) {
267 console.log(new Date.toISOString(), ...args);
268 }
269
270 function unstable_getContext() {
271 let map = new Map();
272 map.set(loggerContext, logger);
273 return map;
274 }
275 ```
276
277## 7.2.0
278
279### Minor Changes
280
281- 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))
282
283 ```tsx
284 import { href } from "react-router";
285
286 export default function Component() {
287 const link = href("/blog/:slug", { slug: "my-first-post" });
288 return (
289 <main>
290 <Link to={href("/products/:id", { id: "asdf" })} />
291 <NavLink to={href("/:lang?/about", { lang: "en" })} />
292 </main>
293 );
294 }
295 ```
296
297### Patch Changes
298
299- Fix typegen for repeated params ([#13012](https://github.com/remix-run/react-router/pull/13012))
300
301 In React Router, path parameters are keyed by their name.
302 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.
303 For example, `/a/1/b/2/c/3` will result in the value `{ id: 3 }` at runtime.
304
305 Previously, generated types for params incorrectly modeled repeated params with an array.
306 So `/a/1/b/2/c/3` generated a type like `{ id: [1,2,3] }`.
307
308 To be consistent with runtime behavior, the generated types now correctly model the "last one wins" semantics of path parameters.
309 So `/a/1/b/2/c/3` now generates a type like `{ id: 3 }`.
310
311- 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))
312
313- Properly handle revalidations to across a prerender/SPA boundary ([#13021](https://github.com/remix-run/react-router/pull/13021))
314
315 - 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
316 - We don't know all the pre-rendered paths client-side, however:
317 - All `loader` data in `ssr:false` mode is static because it's generated at build time
318 - A route must use a `clientLoader` to do anything dynamic
319 - 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
320 - We short circuit and skip single fetch `.data` request logic if there are no server loaders with `shouldLoad=true` in our single fetch `dataStrategy`
321 - This ensures that the route doesn't cause a `.data` request that would 404 after a submission
322
323- 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))
324
325 - A parent route has only a `loader` (does not have a `clientLoader`)
326 - The parent route is pre-rendered
327 - The parent route has children routes which are not prerendered
328 - 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`
329 - This can be resolved by either adding a parent `clientLoader` or pre-rendering the child paths
330 - If you add a `clientLoader`, calling the `serverLoader()` on non-prerendered paths will throw a 404
331
332- Add unstable support for splitting route modules in framework mode via `future.unstable_splitRouteModules` ([#11871](https://github.com/remix-run/react-router/pull/11871))
333
334- 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))
335
336- Align dev server behavior with static file server behavior when `ssr:false` is set ([#12948](https://github.com/remix-run/react-router/pull/12948))
337
338 - When no `prerender` config exists, only SSR down to the root `HydrateFallback` (SPA Mode)
339 - When a `prerender` config exists but the current path is not prerendered, only SSR down to the root `HydrateFallback` (SPA Fallback)
340 - Return a 404 on `.data` requests to non-pre-rendered paths
341
342- Improve prefetch performance of CSS side effects in framework mode ([#12889](https://github.com/remix-run/react-router/pull/12889))
343
344- 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))
345
346 - 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
347 - 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
348
349- Properly handle interrupted manifest requests in lazy route discovery ([#12915](https://github.com/remix-run/react-router/pull/12915))
350
351## 7.1.5
352
353### Patch Changes
354
355- 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))
356
357## 7.1.4
358
359### Patch Changes
360
361- Internal reorg to clean up some duplicated route module types ([#12799](https://github.com/remix-run/react-router/pull/12799))
362- 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))
363- 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))
364 - This only applies when accessed as a resource route without the `.data` extension
365 - When accessed from a Single Fetch `.data` request, they will still be encoded via `turbo-stream`
366- 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))
367- Properly bubble headers as `errorHeaders` when throwing a `data()` result ([#12846](https://github.com/remix-run/react-router/pull/12846))
368 - Avoid duplication of `Set-Cookie` headers could be duplicated if also returned from `headers`
369- Optimize route matching by skipping redundant `matchRoutes` calls when possible ([#12800](https://github.com/remix-run/react-router/pull/12800))
370
371## 7.1.3
372
373_No changes_
374
375## 7.1.2
376
377### Patch Changes
378
379- Fix issue with fetcher data cleanup in the data layer on fetcher unmount ([#12681](https://github.com/remix-run/react-router/pull/12681))
380- Do not rely on `symbol` for filtering out `redirect` responses from loader data ([#12694](https://github.com/remix-run/react-router/pull/12694))
381
382 Previously, some projects were getting type checking errors like:
383
384 ```ts
385 error TS4058: Return type of exported function has or is using name 'redirectSymbol' from external module "node_modules/..." but cannot be named.
386 ```
387
388 Now that `symbol`s are not used for the `redirect` response type, these errors should no longer be present.
389
390## 7.1.1
391
392_No changes_
393
394## 7.1.0
395
396### Patch Changes
397
398- Throw unwrapped single fetch redirect to align with pre-single fetch behavior ([#12506](https://github.com/remix-run/react-router/pull/12506))
399- Ignore redirects when inferring loader data types ([#12527](https://github.com/remix-run/react-router/pull/12527))
400- 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))
401
402## 7.0.2
403
404### Patch Changes
405
406- 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))
407- Generate wide `matches` and `params` types for current route and child routes ([#12397](https://github.com/remix-run/react-router/pull/12397))
408
409 At runtime, `matches` includes child route matches and `params` include child route path parameters.
410 But previously, we only generated types for parent routes in `matches`; for `params`, we only considered the parent routes and the current route.
411 To align our generated types more closely to the runtime behavior, we now generate more permissive, wider types when accessing child route information.
412
413## 7.0.1
414
415_No changes_
416
417## 7.0.0
418
419### Major Changes
420
421- 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))
422
423 - `defer`
424 - `AbortedDeferredError`
425 - `type TypedDeferredData`
426 - `UNSAFE_DeferredData`
427 - `UNSAFE_DEFERRED_SYMBOL`,
428
429- - Collapse `@remix-run/router` into `react-router` ([#11505](https://github.com/remix-run/react-router/pull/11505))
430 - Collapse `react-router-dom` into `react-router`
431 - Collapse `@remix-run/server-runtime` into `react-router`
432 - Collapse `@remix-run/testing` into `react-router`
433
434- Remove single_fetch future flag. ([#11522](https://github.com/remix-run/react-router/pull/11522))
435
436- Drop support for Node 16, React Router SSR now requires Node 18 or higher ([#11391](https://github.com/remix-run/react-router/pull/11391))
437
438- Remove `future.v7_startTransition` flag ([#11696](https://github.com/remix-run/react-router/pull/11696))
439
440- - 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))
441 - `useNavigate()`
442 - `useSubmit`
443 - `useFetcher().load`
444 - `useFetcher().submit`
445 - `useRevalidator.revalidate`
446
447- Remove `future.v7_normalizeFormMethod` future flag ([#11697](https://github.com/remix-run/react-router/pull/11697))
448
449- 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))
450
451 - `createCookie`
452 - `createCookieSessionStorage`
453 - `createMemorySessionStorage`
454 - `createSessionStorage`
455
456 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)
457
458 Since platform-specific packages no longer need to implement this API, the following low-level APIs have been removed:
459
460 - `createCookieFactory`
461 - `createSessionStorageFactory`
462 - `createCookieSessionStorageFactory`
463 - `createMemorySessionStorageFactory`
464
465- Imports/Exports cleanup ([#11840](https://github.com/remix-run/react-router/pull/11840))
466
467 - Removed the following exports that were previously public API from `@remix-run/router`
468 - types
469 - `AgnosticDataIndexRouteObject`
470 - `AgnosticDataNonIndexRouteObject`
471 - `AgnosticDataRouteMatch`
472 - `AgnosticDataRouteObject`
473 - `AgnosticIndexRouteObject`
474 - `AgnosticNonIndexRouteObject`
475 - `AgnosticRouteMatch`
476 - `AgnosticRouteObject`
477 - `TrackedPromise`
478 - `unstable_AgnosticPatchRoutesOnMissFunction`
479 - `Action` -> exported as `NavigationType` via `react-router`
480 - `Router` exported as `DataRouter` to differentiate from RR's `<Router>`
481 - API
482 - `getToPathname` (`@private`)
483 - `joinPaths` (`@private`)
484 - `normalizePathname` (`@private`)
485 - `resolveTo` (`@private`)
486 - `stripBasename` (`@private`)
487 - `createBrowserHistory` -> in favor of `createBrowserRouter`
488 - `createHashHistory` -> in favor of `createHashRouter`
489 - `createMemoryHistory` -> in favor of `createMemoryRouter`
490 - `createRouter`
491 - `createStaticHandler` -> in favor of wrapper `createStaticHandler` in RR Dom
492 - `getStaticContextFromError`
493 - Removed the following exports that were previously public API from `react-router`
494 - `Hash`
495 - `Pathname`
496 - `Search`
497
498- update minimum node version to 18 ([#11690](https://github.com/remix-run/react-router/pull/11690))
499
500- Remove `future.v7_prependBasename` from the ionternalized `@remix-run/router` package ([#11726](https://github.com/remix-run/react-router/pull/11726))
501
502- Migrate Remix type generics to React Router ([#12180](https://github.com/remix-run/react-router/pull/12180))
503
504 - These generics are provided for Remix v2 migration purposes
505 - These generics and the APIs they exist on should be considered informally deprecated in favor of the new `Route.*` types
506 - Anyone migrating from React Router v6 should probably not leverage these new generics and should migrate straight to the `Route.*` types
507 - For React Router v6 users, these generics are new and should not impact your app, with one exception
508 - `useFetcher` previously had an optional generic (used primarily by Remix v2) that expected the data type
509 - This has been updated in v7 to expect the type of the function that generates the data (i.e., `typeof loader`/`typeof action`)
510 - Therefore, you should update your usages:
511 - `useFetcher<LoaderData>()`
512 - `useFetcher<typeof loader>()`
513
514- Remove `future.v7_throwAbortReason` from internalized `@remix-run/router` package ([#11728](https://github.com/remix-run/react-router/pull/11728))
515
516- Add `exports` field to all packages ([#11675](https://github.com/remix-run/react-router/pull/11675))
517
518- node package no longer re-exports from react-router ([#11702](https://github.com/remix-run/react-router/pull/11702))
519
520- renamed RemixContext to FrameworkContext ([#11705](https://github.com/remix-run/react-router/pull/11705))
521
522- updates the minimum React version to 18 ([#11689](https://github.com/remix-run/react-router/pull/11689))
523
524- PrefetchPageDescriptor replaced by PageLinkDescriptor ([#11960](https://github.com/remix-run/react-router/pull/11960))
525
526- - 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))
527 - Examples: `LoaderFunction`, `LoaderFunctionArgs`, `ActionFunction`, `ActionFunctionArgs`, `DataFunctionArgs`, `RouteManifest`, `LinksFunction`, `Route`, `EntryRoute`
528 - The `RouteManifest` type used by the "remix" code is now slightly stricter because it is using the former `@remix-run/router` `RouteManifest`
529 - `Record<string, Route> -> Record<string, Route | undefined>`
530 - Removed `AppData` type in favor of inlining `unknown` in the few locations it was used
531 - Removed `ServerRuntimeMeta*` types in favor of the `Meta*` types they were duplicated from
532
533- - Remove the `future.v7_partialHydration` flag ([#11725](https://github.com/remix-run/react-router/pull/11725))
534 - This also removes the `<RouterProvider fallbackElement>` prop
535 - To migrate, move the `fallbackElement` to a `hydrateFallbackElement`/`HydrateFallback` on your root route
536 - Also worth nothing there is a related breaking changer with this future flag:
537 - Without `future.v7_partialHydration` (when using `fallbackElement`), `state.navigation` was populated during the initial load
538 - With `future.v7_partialHydration`, `state.navigation` remains in an `"idle"` state during the initial load
539
540- Remove `v7_relativeSplatPath` future flag ([#11695](https://github.com/remix-run/react-router/pull/11695))
541
542- Drop support for Node 18, update minimum Node vestion to 20 ([#12171](https://github.com/remix-run/react-router/pull/12171))
543
544 - Remove `installGlobals()` as this should no longer be necessary
545
546- Remove remaining future flags ([#11820](https://github.com/remix-run/react-router/pull/11820))
547
548 - React Router `v7_skipActionErrorRevalidation`
549 - Remix `v3_fetcherPersist`, `v3_relativeSplatPath`, `v3_throwAbortReason`
550
551- rename createRemixStub to createRoutesStub ([#11692](https://github.com/remix-run/react-router/pull/11692))
552
553- Remove `@remix-run/router` deprecated `detectErrorBoundary` option in favor of `mapRouteProperties` ([#11751](https://github.com/remix-run/react-router/pull/11751))
554
555- 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))
556
557 - 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
558 - DOM environments should import from `react-router/dom` to get the proper component that makes `ReactDOM.flushSync()` available:
559 - If you are using the Vite plugin, use this in your `entry.client.tsx`:
560 - `import { HydratedRouter } from 'react-router/dom'`
561 - If you are not using the Vite plugin and are manually calling `createBrowserRouter`/`createHashRouter`:
562 - `import { RouterProvider } from "react-router/dom"`
563
564- Remove `future.v7_fetcherPersist` flag ([#11731](https://github.com/remix-run/react-router/pull/11731))
565
566- 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))
567
568### Minor Changes
569
570- - 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))
571 - 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)
572 - `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.
573
574 ```ts
575 // react-router.config.ts
576 import type { Config } from "@react-router/dev/config";
577
578 export default {
579 async prerender() {
580 let slugs = await fakeGetSlugsFromCms();
581 // Prerender these paths into `.html` files at build time, and `.data`
582 // files if they have loaders
583 return ["/", "/about", ...slugs.map((slug) => `/product/${slug}`)];
584 },
585 } satisfies Config;
586
587 async function fakeGetSlugsFromCms() {
588 await new Promise((r) => setTimeout(r, 1000));
589 return ["shirt", "hat"];
590 }
591 ```
592
593- Params, loader data, and action data as props for route component exports ([#11961](https://github.com/remix-run/react-router/pull/11961))
594
595 ```tsx
596 export default function Component({ params, loaderData, actionData }) {}
597
598 export function HydrateFallback({ params }) {}
599 export function ErrorBoundary({ params, loaderData, actionData }) {}
600 ```
601
602- Remove duplicate `RouterProvider` impliementations ([#11679](https://github.com/remix-run/react-router/pull/11679))
603
604- ### Typesafety improvements ([#12019](https://github.com/remix-run/react-router/pull/12019))
605
606 React Router now generates types for each of your route modules.
607 You can access those types by importing them from `./+types.<route filename without extension>`.
608 For example:
609
610 ```ts
611 // app/routes/product.tsx
612 import type * as Route from "./+types.product";
613
614 export function loader({ params }: Route.LoaderArgs) {}
615
616 export default function Component({ loaderData }: Route.ComponentProps) {}
617 ```
618
619 This initial implementation targets type inference for:
620
621 - `Params` : Path parameters from your routing config in `routes.ts` including file-based routing
622 - `LoaderData` : Loader data from `loader` and/or `clientLoader` within your route module
623 - `ActionData` : Action data from `action` and/or `clientAction` within your route module
624
625 In the future, we plan to add types for the rest of the route module exports: `meta`, `links`, `headers`, `shouldRevalidate`, etc.
626 We also plan to generate types for typesafe `Link`s:
627
628 ```tsx
629 <Link to="/products/:id" params={{ id: 1 }} />
630 // ^^^^^^^^^^^^^ ^^^^^^^^^
631 // typesafe `to` and `params` based on the available routes in your app
632 ```
633
634 Check out our docs for more:
635
636 - [_Explanations > Type Safety_](https://reactrouter.com/dev/guides/explanation/type-safety)
637 - [_How-To > Setting up type safety_](https://reactrouter.com/dev/guides/how-to/setting-up-type-safety)
638
639- Stabilize `unstable_dataStrategy` ([#11969](https://github.com/remix-run/react-router/pull/11969))
640
641- Stabilize `unstable_patchRoutesOnNavigation` ([#11970](https://github.com/remix-run/react-router/pull/11970))
642
643### Patch Changes
644
645- No changes ([`506329c4e`](https://github.com/remix-run/react-router/commit/506329c4e2e7aba9837cbfa44df6103b49423745))
646
647- chore: re-enable development warnings through a `development` exports condition. ([#12269](https://github.com/remix-run/react-router/pull/12269))
648
649- Remove unstable upload handler. ([#12015](https://github.com/remix-run/react-router/pull/12015))
650
651- Remove unneeded dependency on @web3-storage/multipart-parser ([#12274](https://github.com/remix-run/react-router/pull/12274))
652
653- Fix redirects returned from loaders/actions using `data()` ([#12021](https://github.com/remix-run/react-router/pull/12021))
654
655- fix(react-router): (v7) fix static prerender of non-ascii characters ([#12161](https://github.com/remix-run/react-router/pull/12161))
656
657- Replace `substr` with `substring` ([#12080](https://github.com/remix-run/react-router/pull/12080))
658
659- Remove the deprecated `json` utility ([#12146](https://github.com/remix-run/react-router/pull/12146))
660
661 - 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
662
663- Remove unneeded dependency on source-map ([#12275](https://github.com/remix-run/react-router/pull/12275))
664
665## 6.28.0
666
667### Minor Changes
668
669- - Log deprecation warnings for v7 flags ([#11750](https://github.com/remix-run/react-router/pull/11750))
670 - Add deprecation warnings to `json`/`defer` in favor of returning raw objects
671 - These methods will be removed in React Router v7
672
673### Patch Changes
674
675- Update JSDoc URLs for new website structure (add /v6/ segment) ([#12141](https://github.com/remix-run/react-router/pull/12141))
676- Updated dependencies:
677 - `@remix-run/router@1.21.0`
678
679## 6.27.0
680
681### Minor Changes
682
683- Stabilize `unstable_patchRoutesOnNavigation` ([#11973](https://github.com/remix-run/react-router/pull/11973))
684 - Add new `PatchRoutesOnNavigationFunctionArgs` type for convenience ([#11967](https://github.com/remix-run/react-router/pull/11967))
685- Stabilize `unstable_dataStrategy` ([#11974](https://github.com/remix-run/react-router/pull/11974))
686- Stabilize the `unstable_flushSync` option for navigations and fetchers ([#11989](https://github.com/remix-run/react-router/pull/11989))
687- Stabilize the `unstable_viewTransition` option for navigations and the corresponding `unstable_useViewTransitionState` hook ([#11989](https://github.com/remix-run/react-router/pull/11989))
688
689### Patch Changes
690
691- 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))
692
693- 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))
694
695- 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))
696
697- Updated dependencies:
698 - `@remix-run/router@1.20.0`
699
700## 6.26.2
701
702### Patch Changes
703
704- Updated dependencies:
705 - `@remix-run/router@1.19.2`
706
707## 6.26.1
708
709### Patch Changes
710
711- Rename `unstable_patchRoutesOnMiss` to `unstable_patchRoutesOnNavigation` to match new behavior ([#11888](https://github.com/remix-run/react-router/pull/11888))
712- Updated dependencies:
713 - `@remix-run/router@1.19.1`
714
715## 6.26.0
716
717### Minor Changes
718
719- 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))
720
721### Patch Changes
722
723- Fix initial hydration behavior when using `future.v7_partialHydration` along with `unstable_patchRoutesOnMiss` ([#11838](https://github.com/remix-run/react-router/pull/11838))
724 - During initial hydration, `router.state.matches` will now include any partial matches so that we can render ancestor `HydrateFallback` components
725- Updated dependencies:
726 - `@remix-run/router@1.19.0`
727
728## 6.25.1
729
730No 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.
731
732## 6.25.0
733
734### Minor Changes
735
736- Stabilize `future.unstable_skipActionErrorRevalidation` as `future.v7_skipActionErrorRevalidation` ([#11769](https://github.com/remix-run/react-router/pull/11769))
737 - When this flag is enabled, actions will not automatically trigger a revalidation if they return/throw a `Response` with a `4xx`/`5xx` status code
738 - You may still opt-into revalidation via `shouldRevalidate`
739 - This also changes `shouldRevalidate`'s `unstable_actionStatus` parameter to `actionStatus`
740
741### Patch Changes
742
743- Fix regression and properly decode paths inside `useMatch` so matches/params reflect decoded params ([#11789](https://github.com/remix-run/react-router/pull/11789))
744- Updated dependencies:
745 - `@remix-run/router@1.18.0`
746
747## 6.24.1
748
749### Patch Changes
750
751- 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))
752- Updated dependencies:
753 - `@remix-run/router@1.17.1`
754
755## 6.24.0
756
757### Minor Changes
758
759- Add support for Lazy Route Discovery (a.k.a. Fog of War) ([#11626](https://github.com/remix-run/react-router/pull/11626))
760 - RFC: <https://github.com/remix-run/react-router/discussions/11113>
761 - `unstable_patchRoutesOnMiss` docs: <https://reactrouter.com/v6/routers/create-browser-router>
762
763### Patch Changes
764
765- Updated dependencies:
766 - `@remix-run/router@1.17.0`
767
768## 6.23.1
769
770### Patch Changes
771
772- allow undefined to be resolved with `<Await>` ([#11513](https://github.com/remix-run/react-router/pull/11513))
773- Updated dependencies:
774 - `@remix-run/router@1.16.1`
775
776## 6.23.0
777
778### Minor Changes
779
780- Add a new `unstable_dataStrategy` configuration option ([#11098](https://github.com/remix-run/react-router/pull/11098))
781 - This option allows Data Router applications to take control over the approach for executing route loaders and actions
782 - 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
783
784### Patch Changes
785
786- Updated dependencies:
787 - `@remix-run/router@1.16.0`
788
789## 6.22.3
790
791### Patch Changes
792
793- Updated dependencies:
794 - `@remix-run/router@1.15.3`
795
796## 6.22.2
797
798### Patch Changes
799
800- Updated dependencies:
801 - `@remix-run/router@1.15.2`
802
803## 6.22.1
804
805### Patch Changes
806
807- Fix encoding/decoding issues with pre-encoded dynamic parameter values ([#11199](https://github.com/remix-run/react-router/pull/11199))
808- Updated dependencies:
809 - `@remix-run/router@1.15.1`
810
811## 6.22.0
812
813### Patch Changes
814
815- Updated dependencies:
816 - `@remix-run/router@1.15.0`
817
818## 6.21.3
819
820### Patch Changes
821
822- Remove leftover `unstable_` prefix from `Blocker`/`BlockerFunction` types ([#11187](https://github.com/remix-run/react-router/pull/11187))
823
824## 6.21.2
825
826### Patch Changes
827
828- Updated dependencies:
829 - `@remix-run/router@1.14.2`
830
831## 6.21.1
832
833### Patch Changes
834
835- 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))
836- Updated dependencies:
837 - `@remix-run/router@1.14.1`
838
839## 6.21.0
840
841### Minor Changes
842
843- 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))
844
845 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))
846
847 **The Bug**
848 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.
849
850 **The Background**
851 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:
852
853 ```jsx
854 <BrowserRouter>
855 <Routes>
856 <Route path="/" element={<Home />} />
857 <Route path="dashboard/*" element={<Dashboard />} />
858 </Routes>
859 </BrowserRouter>
860 ```
861
862 Any paths like `/dashboard`, `/dashboard/team`, `/dashboard/projects` will match the `Dashboard` route. The dashboard component itself can then render nested `<Routes>`:
863
864 ```jsx
865 function Dashboard() {
866 return (
867 <div>
868 <h2>Dashboard</h2>
869 <nav>
870 <Link to="/">Dashboard Home</Link>
871 <Link to="team">Team</Link>
872 <Link to="projects">Projects</Link>
873 </nav>
874
875 <Routes>
876 <Route path="/" element={<DashboardHome />} />
877 <Route path="team" element={<DashboardTeam />} />
878 <Route path="projects" element={<DashboardProjects />} />
879 </Routes>
880 </div>
881 );
882 }
883 ```
884
885 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.
886
887 **The Problem**
888
889 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 `"."`:
890
891 ```jsx
892 // If we are on URL /dashboard/team, and we want to link to /dashboard/team:
893 function DashboardTeam() {
894 // ❌ This is broken and results in <a href="/dashboard">
895 return <Link to=".">A broken link to the Current URL</Link>;
896
897 // ✅ This is fixed but super unintuitive since we're already at /dashboard/team!
898 return <Link to="./team">A broken link to the Current URL</Link>;
899 }
900 ```
901
902 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.
903
904 Even worse, consider a nested splat route configuration:
905
906 ```jsx
907 <BrowserRouter>
908 <Routes>
909 <Route path="dashboard">
910 <Route path="*" element={<Dashboard />} />
911 </Route>
912 </Routes>
913 </BrowserRouter>
914 ```
915
916 Now, a `<Link to=".">` and a `<Link to="..">` inside the `Dashboard` component go to the same place! That is definitely not correct!
917
918 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:
919
920 ```jsx
921 let router = createBrowserRouter({
922 path: "/dashboard",
923 children: [
924 {
925 path: "*",
926 action: dashboardAction,
927 Component() {
928 // ❌ This form is broken! It throws a 405 error when it submits because
929 // it tries to submit to /dashboard (without the splat value) and the parent
930 // `/dashboard` route doesn't have an action
931 return <Form method="post">...</Form>;
932 },
933 },
934 ],
935 });
936 ```
937
938 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.
939
940 **The Solution**
941 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:
942
943 ```jsx
944 <BrowserRouter>
945 <Routes>
946 <Route path="dashboard">
947 <Route index path="*" element={<Dashboard />} />
948 </Route>
949 </Routes>
950 </BrowserRouter>
951
952 function Dashboard() {
953 return (
954 <div>
955 <h2>Dashboard</h2>
956 <nav>
957 <Link to="..">Dashboard Home</Link>
958 <Link to="../team">Team</Link>
959 <Link to="../projects">Projects</Link>
960 </nav>
961
962 <Routes>
963 <Route path="/" element={<DashboardHome />} />
964 <Route path="team" element={<DashboardTeam />} />
965 <Route path="projects" element={<DashboardProjects />} />
966 </Router>
967 </div>
968 );
969 }
970 ```
971
972 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".
973
974### Patch Changes
975
976- Properly handle falsy error values in ErrorBoundary's ([#11071](https://github.com/remix-run/react-router/pull/11071))
977- Updated dependencies:
978 - `@remix-run/router@1.14.0`
979
980## 6.20.1
981
982### Patch Changes
983
984- 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))
985- Updated dependencies:
986 - `@remix-run/router@1.13.1`
987
988## 6.20.0
989
990### Minor Changes
991
992- Export the `PathParam` type from the public API ([#10719](https://github.com/remix-run/react-router/pull/10719))
993
994### Patch Changes
995
996- Fix bug with `resolveTo` in splat routes ([#11045](https://github.com/remix-run/react-router/pull/11045))
997 - 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`
998 - This removes the `UNSAFE_getPathContributingMatches` export from `@remix-run/router` since we no longer need this in the `react-router`/`react-router-dom` layers
999- Updated dependencies:
1000 - `@remix-run/router@1.13.0`
1001
1002## 6.19.0
1003
1004### Minor Changes
1005
1006- 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))
1007- 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))
1008
1009### Patch Changes
1010
1011- 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))
1012
1013- 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))
1014
1015 - ⚠️ 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.
1016
1017- Updated dependencies:
1018 - `@remix-run/router@1.12.0`
1019
1020## 6.18.0
1021
1022### Patch Changes
1023
1024- 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))
1025- Updated dependencies:
1026 - `@remix-run/router@1.11.0`
1027
1028## 6.17.0
1029
1030### Patch Changes
1031
1032- 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))
1033- Updated dependencies:
1034 - `@remix-run/router@1.10.0`
1035
1036## 6.16.0
1037
1038### Minor Changes
1039
1040- 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))
1041 - `Location` now accepts a generic for the `location.state` value
1042 - `ActionFunctionArgs`/`ActionFunction`/`LoaderFunctionArgs`/`LoaderFunction` now accept a generic for the `context` parameter (only used in SSR usages via `createStaticHandler`)
1043 - 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`
1044- 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))
1045- Export `ShouldRevalidateFunctionArgs` interface ([#10797](https://github.com/remix-run/react-router/pull/10797))
1046- 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))
1047
1048### Patch Changes
1049
1050- Updated dependencies:
1051 - `@remix-run/router@1.9.0`
1052
1053## 6.15.0
1054
1055### Minor Changes
1056
1057- 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))
1058
1059### Patch Changes
1060
1061- Ensure `useRevalidator` is referentially stable across re-renders if revalidations are not actively occurring ([#10707](https://github.com/remix-run/react-router/pull/10707))
1062- Updated dependencies:
1063 - `@remix-run/router@1.8.0`
1064
1065## 6.14.2
1066
1067### Patch Changes
1068
1069- Updated dependencies:
1070 - `@remix-run/router@1.7.2`
1071
1072## 6.14.1
1073
1074### Patch Changes
1075
1076- Fix loop in `unstable_useBlocker` when used with an unstable blocker function ([#10652](https://github.com/remix-run/react-router/pull/10652))
1077- Fix issues with reused blockers on subsequent navigations ([#10656](https://github.com/remix-run/react-router/pull/10656))
1078- Updated dependencies:
1079 - `@remix-run/router@1.7.1`
1080
1081## 6.14.0
1082
1083### Patch Changes
1084
1085- Strip `basename` from locations provided to `unstable_useBlocker` functions to match `useLocation` ([#10573](https://github.com/remix-run/react-router/pull/10573))
1086- Fix `generatePath` when passed a numeric `0` value parameter ([#10612](https://github.com/remix-run/react-router/pull/10612))
1087- Fix `unstable_useBlocker` key issues in `StrictMode` ([#10573](https://github.com/remix-run/react-router/pull/10573))
1088- Fix `tsc --skipLibCheck:false` issues on React 17 ([#10622](https://github.com/remix-run/react-router/pull/10622))
1089- Upgrade `typescript` to 5.1 ([#10581](https://github.com/remix-run/react-router/pull/10581))
1090- Updated dependencies:
1091 - `@remix-run/router@1.7.0`
1092
1093## 6.13.0
1094
1095### Minor Changes
1096
1097- 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))
1098
1099 Existing behavior will no longer include `React.startTransition`:
1100
1101 ```jsx
1102 <BrowserRouter>
1103 <Routes>{/*...*/}</Routes>
1104 </BrowserRouter>
1105
1106 <RouterProvider router={router} />
1107 ```
1108
1109 If you wish to enable `React.startTransition`, pass the future flag to your component:
1110
1111 ```jsx
1112 <BrowserRouter future={{ v7_startTransition: true }}>
1113 <Routes>{/*...*/}</Routes>
1114 </BrowserRouter>
1115
1116 <RouterProvider router={router} future={{ v7_startTransition: true }}/>
1117 ```
1118
1119### Patch Changes
1120
1121- Work around webpack/terser `React.startTransition` minification bug in production mode ([#10588](https://github.com/remix-run/react-router/pull/10588))
1122
1123## 6.12.1
1124
1125> \[!WARNING]
1126> 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.
1127
1128### Patch Changes
1129
1130- Adjust feature detection of `React.startTransition` to fix webpack + react 17 compilation error ([#10569](https://github.com/remix-run/react-router/pull/10569))
1131
1132## 6.12.0
1133
1134### Minor Changes
1135
1136- Wrap internal router state updates with `React.startTransition` if it exists ([#10438](https://github.com/remix-run/react-router/pull/10438))
1137
1138### Patch Changes
1139
1140- Updated dependencies:
1141 - `@remix-run/router@1.6.3`
1142
1143## 6.11.2
1144
1145### Patch Changes
1146
1147- Fix `basename` duplication in descendant `<Routes>` inside a `<RouterProvider>` ([#10492](https://github.com/remix-run/react-router/pull/10492))
1148- Updated dependencies:
1149 - `@remix-run/router@1.6.2`
1150
1151## 6.11.1
1152
1153### Patch Changes
1154
1155- Fix usage of `Component` API within descendant `<Routes>` ([#10434](https://github.com/remix-run/react-router/pull/10434))
1156- Fix bug when calling `useNavigate` from `<Routes>` inside a `<RouterProvider>` ([#10432](https://github.com/remix-run/react-router/pull/10432))
1157- Fix usage of `<Navigate>` in strict mode when using a data router ([#10435](https://github.com/remix-run/react-router/pull/10435))
1158- Updated dependencies:
1159 - `@remix-run/router@1.6.1`
1160
1161## 6.11.0
1162
1163### Patch Changes
1164
1165- Log loader/action errors to the console in dev for easier stack trace evaluation ([#10286](https://github.com/remix-run/react-router/pull/10286))
1166- Fix bug preventing rendering of descendant `<Routes>` when `RouterProvider` errors existed ([#10374](https://github.com/remix-run/react-router/pull/10374))
1167- Fix inadvertent re-renders when using `Component` instead of `element` on a route definition ([#10287](https://github.com/remix-run/react-router/pull/10287))
1168- 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))
1169- 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))
1170- Allow `useRevalidator()` to resolve a loader-driven error boundary scenario ([#10369](https://github.com/remix-run/react-router/pull/10369))
1171- Avoid unnecessary unsubscribe/resubscribes on router state changes ([#10409](https://github.com/remix-run/react-router/pull/10409))
1172- 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))
1173- Updated dependencies:
1174 - `@remix-run/router@1.6.0`
1175
1176## 6.10.0
1177
1178### Minor Changes
1179
1180- 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))
1181
1182 - When `future.v7_normalizeFormMethod === false` (default v6 behavior),
1183 - `useNavigation().formMethod` is lowercase
1184 - `useFetcher().formMethod` is lowercase
1185 - When `future.v7_normalizeFormMethod === true`:
1186 - `useNavigation().formMethod` is uppercase
1187 - `useFetcher().formMethod` is uppercase
1188
1189### Patch Changes
1190
1191- Fix route ID generation when using Fragments in `createRoutesFromElements` ([#10193](https://github.com/remix-run/react-router/pull/10193))
1192- Updated dependencies:
1193 - `@remix-run/router@1.5.0`
1194
1195## 6.9.0
1196
1197### Minor Changes
1198
1199- 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))
1200
1201 **Example JSON Syntax**
1202
1203 ```jsx
1204 // Both of these work the same:
1205 const elementRoutes = [{
1206 path: '/',
1207 element: <Home />,
1208 errorElement: <HomeError />,
1209 }]
1210
1211 const componentRoutes = [{
1212 path: '/',
1213 Component: Home,
1214 ErrorBoundary: HomeError,
1215 }]
1216
1217 function Home() { ... }
1218 function HomeError() { ... }
1219 ```
1220
1221 **Example JSX Syntax**
1222
1223 ```jsx
1224 // Both of these work the same:
1225 const elementRoutes = createRoutesFromElements(
1226 <Route path='/' element={<Home />} errorElement={<HomeError /> } />
1227 );
1228
1229 const componentRoutes = createRoutesFromElements(
1230 <Route path='/' Component={Home} ErrorBoundary={HomeError} />
1231 );
1232
1233 function Home() { ... }
1234 function HomeError() { ... }
1235 ```
1236
1237- **Introducing Lazy Route Modules!** ([#10045](https://github.com/remix-run/react-router/pull/10045))
1238
1239 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`).
1240
1241 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.
1242
1243 Your `lazy` functions will typically return the result of a dynamic import.
1244
1245 ```jsx
1246 // In this example, we assume most folks land on the homepage so we include that
1247 // in our critical-path bundle, but then we lazily load modules for /a and /b so
1248 // they don't load until the user navigates to those routes
1249 let routes = createRoutesFromElements(
1250 <Route path="/" element={<Layout />}>
1251 <Route index element={<Home />} />
1252 <Route path="a" lazy={() => import("./a")} />
1253 <Route path="b" lazy={() => import("./b")} />
1254 </Route>
1255 );
1256 ```
1257
1258 Then in your lazy route modules, export the properties you want defined for the route:
1259
1260 ```jsx
1261 export async function loader({ request }) {
1262 let data = await fetchData(request);
1263 return json(data);
1264 }
1265
1266 // Export a `Component` directly instead of needing to create a React Element from it
1267 export function Component() {
1268 let data = useLoaderData();
1269
1270 return (
1271 <>
1272 <h1>You made it!</h1>
1273 <p>{data}</p>
1274 </>
1275 );
1276 }
1277
1278 // Export an `ErrorBoundary` directly instead of needing to create a React Element from it
1279 export function ErrorBoundary() {
1280 let error = useRouteError();
1281 return isRouteErrorResponse(error) ? (
1282 <h1>
1283 {error.status} {error.statusText}
1284 </h1>
1285 ) : (
1286 <h1>{error.message || error}</h1>
1287 );
1288 }
1289 ```
1290
1291 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.
1292
1293 🙌 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).
1294
1295- Updated dependencies:
1296 - `@remix-run/router@1.4.0`
1297
1298### Patch Changes
1299
1300- Fix `generatePath` incorrectly applying parameters in some cases ([#10078](https://github.com/remix-run/react-router/pull/10078))
1301- Improve memoization for context providers to avoid unnecessary re-renders ([#9983](https://github.com/remix-run/react-router/pull/9983))
1302
1303## 6.8.2
1304
1305### Patch Changes
1306
1307- Updated dependencies:
1308 - `@remix-run/router@1.3.3`
1309
1310## 6.8.1
1311
1312### Patch Changes
1313
1314- Remove inaccurate console warning for POP navigations and update active blocker logic ([#10030](https://github.com/remix-run/react-router/pull/10030))
1315- Updated dependencies:
1316 - `@remix-run/router@1.3.2`
1317
1318## 6.8.0
1319
1320### Patch Changes
1321
1322- Updated dependencies:
1323 - `@remix-run/router@1.3.1`
1324
1325## 6.7.0
1326
1327### Minor Changes
1328
1329- Add `unstable_useBlocker` hook for blocking navigations within the app's location origin ([#9709](https://github.com/remix-run/react-router/pull/9709))
1330
1331### Patch Changes
1332
1333- Fix `generatePath` when optional params are present ([#9764](https://github.com/remix-run/react-router/pull/9764))
1334- Update `<Await>` to accept `ReactNode` as children function return result ([#9896](https://github.com/remix-run/react-router/pull/9896))
1335- Updated dependencies:
1336 - `@remix-run/router@1.3.0`
1337
1338## 6.6.2
1339
1340### Patch Changes
1341
1342- Ensure `useId` consistency during SSR ([#9805](https://github.com/remix-run/react-router/pull/9805))
1343
1344## 6.6.1
1345
1346### Patch Changes
1347
1348- Updated dependencies:
1349 - `@remix-run/router@1.2.1`
1350
1351## 6.6.0
1352
1353### Patch Changes
1354
1355- Prevent `useLoaderData` usage in `errorElement` ([#9735](https://github.com/remix-run/react-router/pull/9735))
1356- Updated dependencies:
1357 - `@remix-run/router@1.2.0`
1358
1359## 6.5.0
1360
1361This 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.
1362
1363**Optional Params Examples**
1364
1365- `<Route path=":lang?/about>` will match:
1366 - `/:lang/about`
1367 - `/about`
1368- `<Route path="/multistep/:widget1?/widget2?/widget3?">` will match:
1369 - `/multistep`
1370 - `/multistep/:widget1`
1371 - `/multistep/:widget1/:widget2`
1372 - `/multistep/:widget1/:widget2/:widget3`
1373
1374**Optional Static Segment Example**
1375
1376- `<Route path="/home?">` will match:
1377 - `/`
1378 - `/home`
1379- `<Route path="/fr?/about">` will match:
1380 - `/about`
1381 - `/fr/about`
1382
1383### Minor Changes
1384
1385- Allows optional routes and optional static segments ([#9650](https://github.com/remix-run/react-router/pull/9650))
1386
1387### Patch Changes
1388
1389- 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))
1390
1391```jsx
1392// Old behavior at URL /prefix-123
1393<Route path="prefix-:id" element={<Comp /> }>
1394
1395function Comp() {
1396 let params = useParams(); // { id: '123' }
1397 let id = params.id; // "123"
1398 ...
1399}
1400
1401// New behavior at URL /prefix-123
1402<Route path=":id" element={<Comp /> }>
1403
1404function Comp() {
1405 let params = useParams(); // { id: 'prefix-123' }
1406 let id = params.id.replace(/^prefix-/, ''); // "123"
1407 ...
1408}
1409```
1410
1411- Updated dependencies:
1412 - `@remix-run/router@1.1.0`
1413
1414## 6.4.5
1415
1416### Patch Changes
1417
1418- Updated dependencies:
1419 - `@remix-run/router@1.0.5`
1420
1421## 6.4.4
1422
1423### Patch Changes
1424
1425- Updated dependencies:
1426 - `@remix-run/router@1.0.4`
1427
1428## 6.4.3
1429
1430### Patch Changes
1431
1432- `useRoutes` should be able to return `null` when passing `locationArg` ([#9485](https://github.com/remix-run/react-router/pull/9485))
1433- fix `initialEntries` type in `createMemoryRouter` ([#9498](https://github.com/remix-run/react-router/pull/9498))
1434- Updated dependencies:
1435 - `@remix-run/router@1.0.3`
1436
1437## 6.4.2
1438
1439### Patch Changes
1440
1441- Fix `IndexRouteObject` and `NonIndexRouteObject` types to make `hasErrorElement` optional ([#9394](https://github.com/remix-run/react-router/pull/9394))
1442- Enhance console error messages for invalid usage of data router hooks ([#9311](https://github.com/remix-run/react-router/pull/9311))
1443- 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))
1444- Updated dependencies:
1445 - `@remix-run/router@1.0.2`
1446
1447## 6.4.1
1448
1449### Patch Changes
1450
1451- Preserve state from `initialEntries` ([#9288](https://github.com/remix-run/react-router/pull/9288))
1452- Updated dependencies:
1453 - `@remix-run/router@1.0.1`
1454
1455## 6.4.0
1456
1457Whoa 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).
1458
1459**New APIs**
1460
1461- Create your router with `createMemoryRouter`
1462- Render your router with `<RouterProvider>`
1463- Load data with a Route `loader` and mutate with a Route `action`
1464- Handle errors with Route `errorElement`
1465- Defer non-critical data with `defer` and `Await`
1466
1467**Bug Fixes**
1468
1469- Path resolution is now trailing slash agnostic (#8861)
1470- `useLocation` returns the scoped location inside a `<Routes location>` component (#9094)
1471
1472**Updated Dependencies**
1473
1474- `@remix-run/router@1.0.0`