react-router
Advanced tools
| --- | ||
| title: Updating from v7 | ||
| order: 2 | ||
| --- | ||
| # Upgrading from v7 | ||
| We try our best to keep major version upgrades simple and boring through the use of opt-in APIs and [Future Flags][api-development-strategy]. Future flags are used to gate breaking changes that don't otherwise have a good call-site opt-in strategy. By adopting all opt-in APIs and future flags, you should be able to upgrade to the next major version of React Router with minimal changes. | ||
| We highly recommend you make a commit after each step and ship it instead of doing everything all at once. Most flags can be adopted in any order, with exceptions noted below. | ||
| ## Minimum Versions | ||
| [MODES: framework, data, declarative] | ||
| <br/> | ||
| <br/> | ||
| React Router v8 requires the following minimum versions. You can prepare for the upgrade by updating them while still on v7: | ||
| - `node@22.22+` | ||
| - `react@19.2.7+`/`react-dom@19.2.7+` | ||
| Framework mode will also require: | ||
| - `vite@7+` (requires `future.v8_viteEnvironmentApi`) | ||
| - also make sure any custom Vite plugins or config are compatible with Vite 7 | ||
| ## Update to latest v7.x | ||
| Before adopting any future flags or call-site opt-in changes, you should update to the latest minor version of v7.x to make sure you have access to the latest flags. You may see a number of deprecation warnings as you upgrade, which we'll cover below. | ||
| π Update to latest v7 | ||
| ```sh | ||
| npm install react-router@7 @react-router/{dev,node,etc.}@7 | ||
| ``` | ||
| ## Future Flags | ||
| ### `future.v8_middleware` | ||
| [MODES: framework, data] | ||
| <br/> | ||
| <br/> | ||
| **Background** | ||
| Middleware allows you to run code before and after the [`Response`][Response] generation for the matched path. This enables common patterns like authentication, logging, error handling, and data preprocessing in a reusable way. Please see the [docs](../how-to/middleware) for more information. | ||
| π **Enable the Flag** | ||
| In Framework mode: | ||
| ```ts filename=react-router.config.ts | ||
| import type { Config } from "@react-router/dev/config"; | ||
| export default { | ||
| future: { | ||
| v8_middleware: true, | ||
| }, | ||
| } satisfies Config; | ||
| ``` | ||
| In Data mode: | ||
| ```ts | ||
| import { createBrowserRouter } from "react-router"; | ||
| const router = createBrowserRouter(routes, { | ||
| future: { | ||
| v8_middleware: true, | ||
| }, | ||
| }); | ||
| ``` | ||
| **Update your Code** | ||
| If you're using the `context` parameter in `loader` and `action` functions, you may need to update your code: | ||
| - In Framework mode, if you're using `react-router-serve`, you should not need to make any updates. Otherwise, this only applies if you have a custom server with a `getLoadContext` function. Please see the docs on the middleware [`getLoadContext` changes](../how-to/middleware#changes-to-getloadcontextapploadcontext) and the instructions to [migrate to the new API](../how-to/middleware#migration-from-apploadcontext). | ||
| - In Data mode, add the `Future` module augmentation described in the [middleware docs](../how-to/middleware#1-typescript-augment-future-for-loaderaction-context) so `context` is typed correctly. | ||
| ### `future.v8_splitRouteModules` | ||
| [MODES: framework] | ||
| <br/> | ||
| <br/> | ||
| **Background** | ||
| This feature enables splitting client-side route exports (`clientLoader`, `clientAction`, `clientMiddleware`, `HydrateFallback`) into separate chunks that can be loaded independently from the route component. This allows these exports to be fetched and executed while the component code is still downloading, improving performance for client-side data loading. | ||
| This can be set to `true` for opt-in behavior, or `"enforce"` to require all routes to be splittable (which will cause build failures for routes that cannot be split due to shared code). | ||
| π **Enable the Flag** | ||
| ```ts filename=react-router.config.ts | ||
| import type { Config } from "@react-router/dev/config"; | ||
| export default { | ||
| future: { | ||
| v8_splitRouteModules: true, | ||
| }, | ||
| } satisfies Config; | ||
| ``` | ||
| **Update your Code** | ||
| No code changes are required. This is an optimization feature that works automatically once enabled. | ||
| ### `future.v8_viteEnvironmentApi` | ||
| [MODES: framework] | ||
| <br/> | ||
| <br/> | ||
| **Background** | ||
| This enables support for the experimental Vite Environment API, which provides a more flexible and powerful way to configure Vite environments. This is only available when using Vite 6+. | ||
| π **Enable the Flag** | ||
| ```ts filename=react-router.config.ts | ||
| import type { Config } from "@react-router/dev/config"; | ||
| export default { | ||
| future: { | ||
| v8_viteEnvironmentApi: true, | ||
| }, | ||
| } satisfies Config; | ||
| ``` | ||
| **Update your Code** | ||
| Most users won't need to make any changes. However, if you have custom Vite configuration that previously relied on the `isSsrBuild` flag β such as a custom server build that sets `build.rollupOptions.input` β you'll need to move that configuration under the per-environment [Environment API][vite-environment] config instead. | ||
| For example, a custom server build should move its SSR `rollupOptions` from the top-level `build` config into `environments.ssr.build`: | ||
| ```diff filename=vite.config.ts | ||
| import { reactRouter } from "@react-router/dev/vite"; | ||
| import { defineConfig } from "vite"; | ||
| -export default defineConfig(({ isSsrBuild }) => ({ | ||
| - build: { | ||
| - rollupOptions: isSsrBuild | ||
| - ? { | ||
| - input: "./server/app.ts", | ||
| - } | ||
| - : undefined, | ||
| - }, | ||
| +export default defineConfig({ | ||
| + environments: { | ||
| + ssr: { | ||
| + build: { | ||
| + rollupOptions: { | ||
| + input: "./server/app.ts", | ||
| + }, | ||
| + }, | ||
| + }, | ||
| + }, | ||
| plugins: [reactRouter()], | ||
| -})); | ||
| +}); | ||
| ``` | ||
| See the [`node-custom-server` template][node-custom-server-template] for a complete example. | ||
| ### `future.v8_passThroughRequests` | ||
| [MODES: framework] | ||
| <br/> | ||
| <br/> | ||
| **Background** | ||
| By default, React Router normalizes the `request.url` passed to your `loader`, `action`, and `middleware` functions by removing React Router's internal implementation details. Specifically, it removes `.data` suffixes and internal search parameters like `?index` and `?_routes`. | ||
| This flag eliminates that normalization and passes the raw HTTP `request` instance to your handlers. This provides a few benefits: | ||
| - Reduces server-side overhead by eliminating multiple `new Request()` calls on the critical path | ||
| - Allows you to distinguish document from data requests in your handlers based on the presence of a `.data` suffix (useful for [observability] purposes) | ||
| If you were previously relying on the normalization of `request.url`, you can switch to use the new sibling `url` parameter which contains a `URL` instance representing the normalized location. | ||
| π **Enable the Flag** | ||
| ```ts filename=react-router.config.ts | ||
| import type { Config } from "@react-router/dev/config"; | ||
| export default { | ||
| future: { | ||
| v8_passThroughRequests: true, | ||
| }, | ||
| } satisfies Config; | ||
| ``` | ||
| **Update your Code** | ||
| If your code relies on inspecting the request URL, you should review it for any assumptions about the URL format: | ||
| ```tsx | ||
| // β Before: assuming no `.data` suffix in `request.url` pathname | ||
| export async function loader({ | ||
| request, | ||
| }: Route.LoaderArgs) { | ||
| let url = new URL(request.url); | ||
| if (url.pathname === "/path") { | ||
| // This check might now behave differently because the request pathname will | ||
| // contain the `.data` suffix on data requests | ||
| } | ||
| } | ||
| // β After: use `url` for normalized routing logic and `request.url` | ||
| // for raw routing logic | ||
| export async function loader({ | ||
| request, | ||
| url, | ||
| }: Route.LoaderArgs) { | ||
| if (url.pathname === "/path") { | ||
| // This will always have the `.data` suffix stripped | ||
| } | ||
| // And now you can distinguish between document versus data requests | ||
| let isDataRequest = new URL( | ||
| request.url, | ||
| ).pathname.endsWith(".data"); | ||
| } | ||
| ``` | ||
| ### `future.v8_trailingSlashAwareDataRequests` | ||
| [MODES: framework] | ||
| <br/> | ||
| <br/> | ||
| **Background** | ||
| React Router serves Framework mode data requests from `.data` URLs. Previously, data requests for routes with and without trailing slashes could map to the same `.data` URL because trailing slashes were not considered during URL generation. This flag preserves trailing slash semantics for data request URLs to avoid ambiguity when your app distinguishes between trailing-slash and non-trailing-slash URLs. | ||
| Currently, your HTTP and `request` pathnames would be as follows for `/a/b/c` and `/a/b/c/` | ||
| | URL `/a/b/c` | **HTTP pathname** | **`request` pathname`** | | ||
| | ------------ | ----------------- | ----------------------- | | ||
| | **Document** | `/a/b/c` | `/a/b/c` β | | ||
| | **Data** | `/a/b/c.data` | `/a/b/c` β | | ||
| | URL `/a/b/c/` | **HTTP pathname** | **`request` pathname`** | | ||
| | ------------- | ----------------- | ----------------------- | | ||
| | **Document** | `/a/b/c/` | `/a/b/c/` β | | ||
| | **Data** | `/a/b/c.data` | `/a/b/c` β οΈ | | ||
| With this flag enabled, these pathnames will be made consistent though a new `_.data` format for client-side `.data` requests: | ||
| | URL `/a/b/c` | **HTTP pathname** | **`request` pathname`** | | ||
| | ------------ | ----------------- | ----------------------- | | ||
| | **Document** | `/a/b/c` | `/a/b/c` β | | ||
| | **Data** | `/a/b/c.data` | `/a/b/c` β | | ||
| | URL `/a/b/c/` | **HTTP pathname** | **`request` pathname`** | | ||
| | ------------- | ------------------ | ----------------------- | | ||
| | **Document** | `/a/b/c/` | `/a/b/c/` β | | ||
| | **Data** | `/a/b/c/_.data` β¬ οΈ | `/a/b/c/` β | | ||
| This flag also aligns the root data request to match this behavior by changing it from `/_root.data` to `/_.data`. | ||
| π **Enable the Flag** | ||
| ```ts filename=react-router.config.ts | ||
| import type { Config } from "@react-router/dev/config"; | ||
| export default { | ||
| future: { | ||
| v8_trailingSlashAwareDataRequests: true, | ||
| }, | ||
| } satisfies Config; | ||
| ``` | ||
| **Update your Code** | ||
| If you have custom app, CDN, cache, or rewrite logic that matches `.data` request URLs, update it to handle the new trailing-slash-aware `/_.data` format. | ||
| ## Other Planned Breaking Changes | ||
| The changes in this section are not controlled by future flags, but you can update your code in v7 to be ready for v8. | ||
| ### `meta` `data` Argument | ||
| [MODES: framework] | ||
| <br/> | ||
| <br/> | ||
| **Background** | ||
| The `data` fields passed to route module `meta` functions are deprecated and will be removed in React Router v8. Use `loaderData` instead on `MetaArgs` and each item in `MetaArgs.matches`. | ||
| π **Update your Code** | ||
| Replace `data` with `loaderData` in your `meta` functions: | ||
| ```diff | ||
| export function meta({ | ||
| - data, | ||
| + loaderData, | ||
| matches, | ||
| }: Route.MetaArgs) { | ||
| return [ | ||
| { | ||
| - title: data.title, | ||
| + title: loaderData.title, | ||
| }, | ||
| ]; | ||
| } | ||
| ``` | ||
| If you read data from parent matches, update those references too: | ||
| ```diff | ||
| export function meta({ matches }: Route.MetaArgs) { | ||
| let rootMatch = matches.find((match) => match.id === "root"); | ||
| - let rootData = rootMatch?.data; | ||
| + let rootData = rootMatch?.loaderData; | ||
| return [{ title: rootData?.siteTitle }]; | ||
| } | ||
| ``` | ||
| ### `react-router-dom` | ||
| [MODES: framework, data, declarative] | ||
| <br/> | ||
| <br/> | ||
| **Background** | ||
| React Router v8 will remove the `react-router-dom` re-export package. In v8, you should import DOM-specific APIs from `react-router/dom` and everything else from `react-router`. | ||
| π **Update your Code** | ||
| Uninstall `react-router-dom`: | ||
| ```sh | ||
| npm uninstall react-router-dom | ||
| ``` | ||
| Replace `react-router-dom` imports with `react-router` imports: | ||
| ```diff | ||
| -import { Link, useLocation } from "react-router-dom"; | ||
| +import { Link, useLocation } from "react-router"; | ||
| ``` | ||
| For DOM-specific APIs, import from `react-router/dom`: | ||
| ```diff | ||
| -import { RouterProvider } from "react-router-dom"; | ||
| +import { RouterProvider } from "react-router/dom"; | ||
| ``` | ||
| ### Cloudflare Vite Plugin | ||
| [MODES: framework] | ||
| <br/> | ||
| <br/> | ||
| **Background** | ||
| React Router v8 will remove the React Router Cloudflare dev proxy. Cloudflare projects should use [`@cloudflare/vite-plugin`][cloudflare-vite-plugin] instead. | ||
| π **Update your Code** | ||
| Replace `cloudflareDevProxy` with `cloudflare`: | ||
| ```diff filename=vite.config.ts | ||
| import { reactRouter } from "@react-router/dev/vite"; | ||
| -import { cloudflareDevProxy } from "@react-router/dev/vite/cloudflare"; | ||
| +import { cloudflare } from "@cloudflare/vite-plugin"; | ||
| import { defineConfig } from "vite"; | ||
| export default defineConfig({ | ||
| plugins: [ | ||
| - cloudflareDevProxy(), | ||
| + cloudflare(), | ||
| reactRouter(), | ||
| ], | ||
| }); | ||
| ``` | ||
| ### `@react-router/architect` `useRequestContextDomainName` | ||
| [MODES: framework] | ||
| <br/> | ||
| <br/> | ||
| **Background** | ||
| The `@react-router/architect` adapter currently uses `X-Forwarded-Host` when creating the `request`, falling back to the `Host` header. In React Router v8, the adapter will use `event.requestContext.domainName` by default, falling back to the `Host` header. | ||
| π **Update your Code** | ||
| Opt in to the v8 behavior now by passing `useRequestContextDomainName: true`: | ||
| ```ts | ||
| import { createRequestHandler } from "@react-router/architect"; | ||
| import * as build from "./build/server"; | ||
| export const handler = createRequestHandler({ | ||
| build, | ||
| useRequestContextDomainName: true, | ||
| }); | ||
| ``` | ||
| This option will be removed in v8 once the `event.requestContext.domainName` behavior is the default. | ||
| ## Upgrade to v8 | ||
| Now that your app is caught up, you can simply update to v8 (theoretically!) without issue. | ||
| ```shellscript nonumber | ||
| # data/declarative mode | ||
| npm install react-router@latest | ||
| # framework mode | ||
| npm install react-router@latest @react-router/{dev,node,etc.}@latest | ||
| ``` | ||
| Congratulations, you're now on v8! | ||
| [api-development-strategy]: ../community/api-development-strategy | ||
| [observability]: ../how-to/instrumentation | ||
| [Response]: https://developer.mozilla.org/en-US/docs/Web/API/Response | ||
| [vite-environment]: https://vite.dev/guide/api-environment | ||
| [node-custom-server-template]: https://github.com/remix-run/react-router-templates/blob/7c617a435510bc3add3a5395c07bc65328b65e9e/node-custom-server/vite.config.ts | ||
| [cloudflare-vite-plugin]: https://developers.cloudflare.com/workers/vite-plugin/ |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -25,3 +25,3 @@ * Copyright (c) Remix Software Inc. | ||
| try { | ||
| if (isBrowser) window.__reactRouterVersion = "8.0.0-pre.1"; | ||
| if (isBrowser) window.__reactRouterVersion = "8.0.0"; | ||
| } catch (e) {} | ||
@@ -28,0 +28,0 @@ /** |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -25,3 +25,3 @@ * Copyright (c) Remix Software Inc. | ||
| try { | ||
| if (isBrowser) window.__reactRouterVersion = "8.0.0-pre.1"; | ||
| if (isBrowser) window.__reactRouterVersion = "8.0.0"; | ||
| } catch (e) {} | ||
@@ -28,0 +28,0 @@ /** |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
| /** | ||
| * react-router v8.0.0-pre.1 | ||
| * react-router v8.0.0 | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
@@ -94,20 +94,14 @@ --- | ||
| ### 3. Update your `getLoadContext` function (if applicable) | ||
| ### 3. Add a `getLoadContext` function (if applicable) | ||
| If you're using a custom server and a `getLoadContext` function, you will need to update your implementation to return an instance of [`RouterContextProvider`][RouterContextProvider], instead of a JavaScript object: | ||
| If you're using a custom server, you can use a `getLoadContext` function to pass information to into the react router handlers: | ||
| ```diff | ||
| +import { | ||
| + createContext, | ||
| + RouterContextProvider, | ||
| +} from "react-router"; | ||
| import { createDb } from "./db"; | ||
| ```tsx | ||
| import { RouterContextProvider } from "react-router"; | ||
| import { dbContext, createDb } from "./db"; | ||
| +const dbContext = createContext<Database>(); | ||
| function getLoadContext(req, res) { | ||
| - return { db: createDb() }; | ||
| + const context = new RouterContextProvider(); | ||
| + context.set(dbContext, createDb()); | ||
| + return context; | ||
| const context = new RouterContextProvider(); | ||
| context.set(dbContext, createDb()); | ||
| return context; | ||
| } | ||
@@ -478,68 +472,2 @@ ``` | ||
| ## Changes to `getLoadContext`/`AppLoadContext` | ||
| <docs-info>This only applies if you are using a custom server and a custom `getLoadContext` function</docs-info> | ||
| Middleware introduces a breaking change to the `context` parameter generated by `getLoadContext` and passed to your `action`s and `loader`s. The current approach of a module-augmented `AppLoadContext` isn't really type-safe and instead just sort of tells TypeScript to "trust me". | ||
| Middleware needs an equivalent `context` on the client for `clientMiddleware`, but we didn't want to duplicate this pattern from the server that we already weren't thrilled with, so we decided to introduce a new API where we could tackle type-safety. | ||
| When opting into middleware, the `context` parameter changes to an instance of [`RouterContextProvider`][RouterContextProvider]: | ||
| ```ts | ||
| let dbContext = createContext<Database>(); | ||
| let context = new RouterContextProvider(); | ||
| context.set(dbContext, getDb()); | ||
| // ^ type-safe | ||
| let db = context.get(dbContext); | ||
| // ^ Database | ||
| ``` | ||
| If you're using a custom server and a `getLoadContext` function, you will need to update your implementation to return an instance of [`RouterContextProvider`][RouterContextProvider], instead of a plain JavaScript object: | ||
| ```diff | ||
| +import { | ||
| + createContext, | ||
| + RouterContextProvider, | ||
| +} from "react-router"; | ||
| import { createDb } from "./db"; | ||
| +const dbContext = createContext<Database>(); | ||
| function getLoadContext(req, res) { | ||
| - return { db: createDb() }; | ||
| + const context = new RouterContextProvider(); | ||
| + context.set(dbContext, createDb()); | ||
| + return context; | ||
| } | ||
| ``` | ||
| ### Migration from `AppLoadContext` | ||
| If you're currently using `AppLoadContext`, you can migrate incrementally by using your existing module augmentation to augment [`RouterContextProvider`][RouterContextProvider] instead of `AppLoadContext`. Then, update your `getLoadContext` function to return an instance of [`RouterContextProvider`][RouterContextProvider]: | ||
| ```diff | ||
| declare module "react-router" { | ||
| - interface AppLoadContext { | ||
| + interface RouterContextProvider { | ||
| db: Database; | ||
| user: User; | ||
| } | ||
| } | ||
| function getLoadContext() { | ||
| const loadContext = {...}; | ||
| - return loadContext; | ||
| + let context = new RouterContextProvider(); | ||
| + Object.assign(context, loadContext); | ||
| + return context; | ||
| } | ||
| ``` | ||
| This allows you to leave your `action`s/`loader`s untouched during initial adoption of middleware, since they can still read values directly (i.e., `context.db`). | ||
| <docs-warning>This approach is only intended to be used as a migration strategy when adopting middleware in React Router v7, allowing you to incrementally migrate to `context.set`/`context.get`. It is not safe to assume this approach will work in the next major version of React Router.</docs-warning> | ||
| <docs-warning>The [`RouterContextProvider`][RouterContextProvider] class is also used for the client-side `context` parameter via `<HydratedRouter getContext>` and `<RouterProvider getContext>`. Since `AppLoadContext` is primarily intended as a hand-off from your HTTP server into the React Router handlers, you need to be aware that these augmented fields will not be available in `clientMiddleware`, `clientLoader`, or `clientAction` functions even thought TypeScript will tell you they are (unless, of course, you provide the fields via `getContext` on the client).</docs-warning> | ||
| ## Common Patterns | ||
@@ -705,20 +633,11 @@ | ||
| [future-flags]: ../upgrading/future | ||
| [Response]: https://developer.mozilla.org/en-US/docs/Web/API/Response | ||
| [common-patterns]: #common-patterns | ||
| [server-client]: #server-vs-client-middleware | ||
| [create-browser-router]: ../api/data-routers/createBrowserRouter | ||
| [create-hash-router]: ../api/data-routers/createHashRouter | ||
| [create-memory-router]: ../api/data-routers/createMemoryRouter | ||
| [create-static-handler]: ../api/data-routers/createStaticHandler | ||
| [framework-action]: ../start/framework/route-module#action | ||
| [framework-loader]: ../start/framework/route-module#loader | ||
| [getloadcontext]: #changes-to-getloadcontextapploadcontext | ||
| [datastrategy]: ../api/data-routers/createBrowserRouter#optsdatastrategy | ||
| [cms-redirect]: #cms-redirect-on-404 | ||
| [createContext]: ../api/utils/createContext | ||
| [RouterContextProvider]: ../api/utils/RouterContextProvider | ||
| [getContext]: ../api/data-routers/createBrowserRouter#optsgetContext | ||
| [window]: https://developer.mozilla.org/en-US/docs/Web/API/Window | ||
| [document]: https://developer.mozilla.org/en-US/docs/Web/API/Document | ||
| [request]: https://developer.mozilla.org/en-US/docs/Web/API/Request | ||
@@ -725,0 +644,0 @@ [data-action]: ../start/data/route-object#action |
@@ -57,3 +57,3 @@ --- | ||
| // throw to ErrorBoundary | ||
| throw data(null, { status: 404 }); | ||
| throw data("Not Found", { status: 404 }); | ||
| } | ||
@@ -60,0 +60,0 @@ return project; |
+3
-6
@@ -8,3 +8,3 @@ --- | ||
| React Router is a multi-strategy router for React bridging the gap from React 18 to React 19. You can use it maximally as a React framework or as minimally as you want. | ||
| React Router is a multi-strategy router for React. You can use it maximally as a React framework or as minimally as you want. | ||
@@ -33,9 +33,6 @@ ## Getting Started | ||
| [Autogenerated Reference Docs β](https://api.reactrouter.com/v7/) | ||
| [Autogenerated Reference Docs β](https://api.reactrouter.com/v8/) | ||
| ## Upgrading | ||
| If you are caught up on future flags, upgrading from React Router v6 or Remix v2 is generally non-breaking. Remix v2 apps are encouraged to upgrade to React Router v7. | ||
| - [Upgrade from v6](./upgrading/v6) | ||
| - [Upgrade from Remix](./upgrading/remix) | ||
| If you are caught up on future flags, [upgrading from React Router v7](./upgrading/v7) is generally non-breaking. |
@@ -100,2 +100,2 @@ --- | ||
| DeployHQ maintains their own guide for deploying React Router v7 to your own server. Checkout the [DeployHQ Guide](https://www.deployhq.com/guides/deploy-react-router-from-github) for more information. | ||
| DeployHQ maintains their own guide for deploying React Router to your own server. Checkout the [DeployHQ Guide](https://www.deployhq.com/guides/deploy-react-router-from-github) for more information. |
@@ -101,3 +101,2 @@ --- | ||
| - might want to server render, might not | ||
| - are coming from Remix (React Router v7 is the "next version" after Remix v2) | ||
| - are migrating from Next.js | ||
@@ -117,3 +116,3 @@ | ||
| - want to use React Router as simply as possible | ||
| - are coming from v6 and are happy with the `<BrowserRouter>` | ||
| - are coming from earlier React Router versions and are happy with the `<BrowserRouter>` | ||
| - have a data layer that either skips pending states (like local first, background data replication/sync) or has its own abstractions for them | ||
@@ -120,0 +119,0 @@ - are coming from Create React App (you may want to consider framework mode though) |
@@ -31,4 +31,4 @@ --- | ||
| - Node.js 20+ (if using Node as your runtime) | ||
| - Vite 5+ | ||
| - Node.js 22.22.0+ | ||
| - Vite 7+ or Vite 8+ | ||
@@ -35,0 +35,0 @@ ## 1. Install the Vite plugin |
+58
-11
| --- | ||
| title: Future Flags | ||
| title: Future Changes | ||
| order: 1 | ||
| --- | ||
| # Future Flags and Deprecations | ||
| # Future Changes | ||
| This guide walks you through the process of adopting future flags in your React Router app. By following this strategy, you will be able to upgrade to the next major version of React Router with minimal changes. To read more about future flags see [API Development Strategy][api-development-strategy]. | ||
| We try our best to keep major version upgrades simple and boring through the use of opt-in APIs and [Future Flags][api-development-strategy]. Future flags are used to gate breaking changes that don't otherwise have a good call-site opt-in strategy. By adopting all opt-in APIs and future flags, you should be able to upgrade to the next major version of React Router with minimal changes. | ||
| We plan to ship new major versions roughly once a year as described in our [Open Governance Model][governance], so this guide will continue to track future changes you can adopt ahead of the next major release. v9 is currently estimated for mid-2027 when Node 22 reaches EOL. | ||
| We highly recommend you make a commit after each step and ship it instead of doing everything all at once. Most flags can be adopted in any order, with exceptions noted below. | ||
| ## Update to latest v7.x | ||
| <docs-info>This is an evolving document that will be updated throughout the duration of v8</docs-info> | ||
| First update to the latest minor version of v7.x to have the latest future flags. You may see a number of deprecation warnings as you upgrade, which we'll cover below. | ||
| ## Minimum Versions | ||
| π Update to latest v7 | ||
| [MODES: framework, data, declarative] | ||
| <br/> | ||
| <br/> | ||
| React Router v9 will require the following minimum versions (as of now). You can prepare for the upgrade by updating them while still on v8: | ||
| - `node@24+` | ||
| ## Update to latest v8.x | ||
| Before adopting any future flags or call-site opt-in changes, you should update to the latest minor version of v8.x to make sure you have access to the latest flags. You may see a number of deprecation warnings as you upgrade, which we'll cover below. | ||
| π Update to latest v8 | ||
| ```sh | ||
| npm install react-router@7 @react-router/{dev,node,etc.}@7 | ||
| npm install react-router@8 @react-router/{dev,node,etc.}@8 | ||
| ``` | ||
| ## Future Flags | ||
| _No future flags yet_ | ||
| ## Other Planned Breaking Changes | ||
| _No known planned breaking changes yet_ | ||
| ## Unstable Future Flags (Optional) | ||
| We document some [unstable] flags here as a reference for folks contributing to the project via beta testing, but they are not generally recommended for production use and may having breaking changes patch/minor releases - adopt with caution! | ||
| We document some [unstable] flags here as a reference for folks contributing to the project via beta testing, but they are not generally recommended for production use and may have breaking changes in patch or minor releases - adopt with caution! | ||
| _No current unstable flags to document_ | ||
| ### `future.unstable_optimizeDeps` | ||
| [MODES: framework] | ||
| <br/> | ||
| <br/> | ||
| **Background** | ||
| This flag lets React Router provide Vite's dependency optimizer with the client entry file and route module files. This can improve dependency optimization in development, but the behavior is still experimental. | ||
| π **Enable the Flag** | ||
| ```ts filename=react-router.config.ts | ||
| import type { Config } from "@react-router/dev/config"; | ||
| export default { | ||
| future: { | ||
| unstable_optimizeDeps: true, | ||
| }, | ||
| } satisfies Config; | ||
| ``` | ||
| **Update your Code** | ||
| No code changes are required. If you run into dependency optimization issues after enabling this flag, remove the flag and restart the dev server. | ||
| [api-development-strategy]: ../community/api-development-strategy | ||
| [governance]: https://github.com/remix-run/react-router/blob/main/GOVERNANCE.md#design-goals | ||
| [unstable]: ../community/api-development-strategy#unstable-flags | ||
| [observability]: ../how-to/instrumentation | ||
| [vite-environment]: https://vite.dev/guide/api-environment |
@@ -29,4 +29,4 @@ --- | ||
| - Node.js 20+ (if using Node as your runtime) | ||
| - Vite 5+ | ||
| - Node.js 22.22.0+ | ||
| - Vite 7+ or Vite 8+ | ||
@@ -280,3 +280,6 @@ ## 1. Move route definitions into route modules | ||
| import ReactDOM from "react-dom/client"; | ||
| import { BrowserRouter } from "react-router"; | ||
| import { | ||
| createBrowserRouter, | ||
| RouterProvider, | ||
| } from "react-router"; | ||
| import App from "./App"; | ||
@@ -283,0 +286,0 @@ |
+6
-6
| { | ||
| "name": "react-router", | ||
| "type": "module", | ||
| "version": "8.0.0-pre.1", | ||
| "version": "8.0.0", | ||
| "description": "Declarative routing for React", | ||
@@ -88,5 +88,5 @@ "keywords": [ | ||
| "premove": "^4.0.0", | ||
| "react": "^19.2.6", | ||
| "react-dom": "^19.2.6", | ||
| "react-test-renderer": "^19.2.6", | ||
| "react": "^19.2.7", | ||
| "react-dom": "^19.2.7", | ||
| "react-test-renderer": "^19.2.7", | ||
| "tsdown": "^0.22.0", | ||
@@ -98,4 +98,4 @@ "typescript": "^6.0.3", | ||
| "peerDependencies": { | ||
| "react": ">=19.2.6", | ||
| "react-dom": ">=19.2.6" | ||
| "react": ">=19.2.7", | ||
| "react-dom": ">=19.2.7" | ||
| }, | ||
@@ -102,0 +102,0 @@ "peerDependenciesMeta": { |
| --- | ||
| title: Upgrading from Remix | ||
| order: 3 | ||
| --- | ||
| # Upgrading from Remix | ||
| <docs-info> | ||
| React Router v7 requires the following minimum versions: | ||
| - `node@20` | ||
| - `react@18` | ||
| - `react-dom@18` | ||
| </docs-info> | ||
| React Router v7 is the next major version of Remix after v2 (see our ["Incremental Path to React 19" blog post][incremental-path-to-react-19] for more information). | ||
| If you have enabled all [Remix v2 future flags][v2-future-flags], upgrading from Remix v2 to React Router v7 mainly involves updating dependencies. | ||
| <docs-info> | ||
| The majority of steps 2-8 can be automatically updated using a [codemod][codemod] created by community member [James Restall][jrestall]. | ||
| </docs-info> | ||
| ## 1. Adopt future flags | ||
| **π Adopt future flags** | ||
| Adopt all existing [future flags][v2-future-flags] in your Remix v2 application. | ||
| ## 2. Update dependencies | ||
| Most of the "shared" APIs that used to be re-exported through the runtime-specific packages (`@remix-run/node`, `@remix-run/cloudflare`, etc.) have all been collapsed into `react-router` in v7. So instead of importing from `@react-router/node` or `@react-router/cloudflare`, you'll import those directly from `react-router`. | ||
| ```diff | ||
| -import { redirect } from "@remix-run/node"; | ||
| +import { redirect } from "react-router"; | ||
| ``` | ||
| The only APIs you should be importing from the runtime-specific packages in v7 are APIs that are specific to that runtime, such as `createFileSessionStorage` for Node and `createWorkersKVSessionStorage` for Cloudflare. | ||
| **π Run the codemod (automated)** | ||
| You can automatically update your packages and imports with the following [codemod][codemod]. This codemod updates all of your packages and imports. Be sure to commit any pending changes before running the codemod, in case you need to revert. | ||
| ```shellscript nonumber | ||
| npx codemod remix/2/react-router/upgrade | ||
| ``` | ||
| **π Install the new dependencies** | ||
| After the codemod updates your dependencies, you need to install the dependencies to remove Remix packages and add the new React Router packages. | ||
| ```shellscript nonumber | ||
| npm install | ||
| ``` | ||
| **π Update your dependencies (manual)** | ||
| If you prefer not to use the codemod, you can manually update your dependencies. | ||
| <details> | ||
| <summary>Expand to see a table of package name changes in alphabetical order</summary> | ||
| | Remix v2 Package | | React Router v7 Package | | ||
| | ---------------------------------- | --- | ------------------------------------------- | | ||
| | `@remix-run/architect` | β‘οΈ | `@react-router/architect` | | ||
| | `@remix-run/cloudflare` | β‘οΈ | `@react-router/cloudflare` | | ||
| | `@remix-run/dev` | β‘οΈ | `@react-router/dev` | | ||
| | `@remix-run/express` | β‘οΈ | `@react-router/express` | | ||
| | `@remix-run/fs-routes` | β‘οΈ | `@react-router/fs-routes` | | ||
| | `@remix-run/node` | β‘οΈ | `@react-router/node` | | ||
| | `@remix-run/react` | β‘οΈ | `react-router` | | ||
| | `@remix-run/route-config` | β‘οΈ | `@react-router/dev` | | ||
| | `@remix-run/routes-option-adapter` | β‘οΈ | `@react-router/remix-routes-option-adapter` | | ||
| | `@remix-run/serve` | β‘οΈ | `@react-router/serve` | | ||
| | `@remix-run/server-runtime` | β‘οΈ | `react-router` | | ||
| | `@remix-run/testing` | β‘οΈ | `react-router` | | ||
| </details> | ||
| ## 3. Change `scripts` in `package.json` | ||
| <docs-info> | ||
| If you used the codemod you can skip this step as it was automatically completed. | ||
| </docs-info> | ||
| **π Update the scripts in your `package.json`** | ||
| | Script | Remix v2 | | React Router v7 | | ||
| | ----------- | ----------------------------------- | --- | ------------------------------------------ | | ||
| | `dev` | `remix vite:dev` | β‘οΈ | `react-router dev` | | ||
| | `build` | `remix vite:build` | β‘οΈ | `react-router build` | | ||
| | `start` | `remix-serve build/server/index.js` | β‘οΈ | `react-router-serve build/server/index.js` | | ||
| | `typecheck` | `tsc` | β‘οΈ | `react-router typegen && tsc` | | ||
| ## 4. Add a `routes.ts` file | ||
| <docs-info> | ||
| If you used the codemod _and_ Remix v2 `v3_routeConfig` flag, you can skip this step as it was automatically completed. | ||
| </docs-info> | ||
| In React Router v7 you define your routes using the `app/routes.ts` file. View the [routing documentation][routing] for more information. | ||
| **π Update dependencies (if using Remix v2 `v3_routeConfig` flag)** | ||
| ```diff filename=app/routes.ts | ||
| -import { type RouteConfig } from "@remix-run/route-config"; | ||
| -import { flatRoutes } from "@remix-run/fs-routes"; | ||
| -import { remixRoutesOptionAdapter } from "@remix-run/routes-option-adapter"; | ||
| +import { type RouteConfig } from "@react-router/dev/routes"; | ||
| +import { flatRoutes } from "@react-router/fs-routes"; | ||
| +import { remixRoutesOptionAdapter } from "@react-router/remix-routes-option-adapter"; | ||
| export default [ | ||
| // however your routes are defined | ||
| ] satisfies RouteConfig; | ||
| ``` | ||
| **π Add a `routes.ts` file (if _not_ using Remix v2 `v3_routeConfig` flag)** | ||
| ```shellscript nonumber | ||
| touch app/routes.ts | ||
| ``` | ||
| For backwards-compatibility, there are a few ways to adopt `routes.ts` to align with your route setup in Remix v2: | ||
| 1. If you were using the "flat routes" [file-based convention][fs-routing], you can continue to use that via the new `@react-router/fs-routes` package: | ||
| ```ts filename=app/routes.ts | ||
| import { type RouteConfig } from "@react-router/dev/routes"; | ||
| import { flatRoutes } from "@react-router/fs-routes"; | ||
| export default flatRoutes() satisfies RouteConfig; | ||
| ``` | ||
| 2. If you were using the "nested" convention from Remix v1 via the `@remix-run/v1-route-convention` package, you can continue using that as well in conjunction with `@react-router/remix-routes-option-adapter`: | ||
| ```ts filename=app/routes.ts | ||
| import { type RouteConfig } from "@react-router/dev/routes"; | ||
| import { remixRoutesOptionAdapter } from "@react-router/remix-routes-option-adapter"; | ||
| import { createRoutesFromFolders } from "@remix-run/v1-route-convention"; | ||
| export default remixRoutesOptionAdapter( | ||
| createRoutesFromFolders, | ||
| ) satisfies RouteConfig; | ||
| ``` | ||
| 3. If you were using the `routes` option to define config-based routes, you can keep that config via `@react-router/remix-routes-option-adapter`: | ||
| ```ts filename=app/routes.ts | ||
| import { type RouteConfig } from "@react-router/dev/routes"; | ||
| import { remixRoutesOptionAdapter } from "@react-router/remix-routes-option-adapter"; | ||
| export default remixRoutesOptionAdapter( | ||
| (defineRoutes) => { | ||
| return defineRoutes((route) => { | ||
| route("/", "home/route.tsx", { index: true }); | ||
| route("about", "about/route.tsx"); | ||
| route("", "concerts/layout.tsx", () => { | ||
| route("trending", "concerts/trending.tsx"); | ||
| route(":city", "concerts/city.tsx"); | ||
| }); | ||
| }); | ||
| }, | ||
| ) satisfies RouteConfig; | ||
| ``` | ||
| - Be sure to also remove the `routes` option in your `vite.config.ts`: | ||
| ```diff filename=vite.config.ts | ||
| export default defineConfig({ | ||
| plugins: [ | ||
| remix({ | ||
| ssr: true, | ||
| - ignoredRouteFiles: ['**/*'], | ||
| - routes(defineRoutes) { | ||
| - return defineRoutes((route) => { | ||
| - route("/somewhere/cool/*", "catchall.tsx"); | ||
| - }); | ||
| - }, | ||
| }) | ||
| tsconfigPaths(), | ||
| ], | ||
| }); | ||
| ``` | ||
| ## 5. Add a React Router config | ||
| **π Add `react-router.config.ts` your project** | ||
| The config that was previously passed to the `remix` plugin in `vite.config.ts` is now exported from `react-router.config.ts`. | ||
| Note: At this point you should remove the v3 future flags you added in step 1. | ||
| ```shellscript nonumber | ||
| touch react-router.config.ts | ||
| ``` | ||
| ```diff filename=vite.config.ts | ||
| export default defineConfig({ | ||
| plugins: [ | ||
| - remix({ | ||
| - ssr: true, | ||
| - future: {/* all the v3 flags */} | ||
| - }), | ||
| + reactRouter(), | ||
| tsconfigPaths(), | ||
| ], | ||
| }); | ||
| ``` | ||
| ```diff filename=react-router.config.ts | ||
| +import type { Config } from "@react-router/dev/config"; | ||
| +export default { | ||
| + ssr: true, | ||
| +} satisfies Config; | ||
| ``` | ||
| ## 6. Add React Router plugin to `vite.config` | ||
| <docs-info> | ||
| If you used the codemod you can skip this step as it was automatically completed. | ||
| </docs-info> | ||
| **π Add `reactRouter` plugin to `vite.config`** | ||
| Change `vite.config.ts` to import and use the new `reactRouter` plugin from `@react-router/dev/vite`: | ||
| ```diff filename=vite.config.ts | ||
| -import { vitePlugin as remix } from "@remix-run/dev"; | ||
| +import { reactRouter } from "@react-router/dev/vite"; | ||
| import { defineConfig } from "vite"; | ||
| import tsconfigPaths from "vite-tsconfig-paths"; | ||
| export default defineConfig({ | ||
| plugins: [ | ||
| - remix(), | ||
| + reactRouter(), | ||
| tsconfigPaths(), | ||
| ], | ||
| }); | ||
| ``` | ||
| ## 7. Enable type safety | ||
| <docs-info> | ||
| If you are not using TypeScript, you can skip this step. | ||
| </docs-info> | ||
| React Router automatically generates types for your route modules into a `.react-router/` directory at the root of your app. This directory is fully managed by React Router and should be gitignore'd. Learn more about the [new type safety features][type-safety]. | ||
| **π Add `.react-router/` to `.gitignore`** | ||
| ```txt | ||
| .react-router/ | ||
| ``` | ||
| **π Update `tsconfig.json`** | ||
| Update the `types` field in your `tsconfig.json` to include: | ||
| - `.react-router/types/**/*` path in the `include` field | ||
| - The appropriate `@react-router/*` package in the `types` field | ||
| - `rootDirs` for simplified relative imports | ||
| ```diff filename=tsconfig.json | ||
| { | ||
| "include": [ | ||
| /* ... */ | ||
| + ".react-router/types/**/*" | ||
| ], | ||
| "compilerOptions": { | ||
| - "types": ["@remix-run/node", "vite/client"], | ||
| + "types": ["@react-router/node", "vite/client"], | ||
| /* ... */ | ||
| + "rootDirs": [".", "./.react-router/types"] | ||
| } | ||
| } | ||
| ``` | ||
| ## 8. Rename components in entry files | ||
| <docs-info> | ||
| If you used the codemod you can skip this step as it was automatically completed. | ||
| </docs-info> | ||
| If you have an `entry.server.tsx` and/or an `entry.client.tsx` file in your application, you will need to update the main components in these files: | ||
| ```diff filename=app/entry.server.tsx | ||
| -import { RemixServer } from "@remix-run/react"; | ||
| +import { ServerRouter } from "react-router"; | ||
| -<RemixServer context={remixContext} url={request.url} />, | ||
| +<ServerRouter context={remixContext} url={request.url} />, | ||
| ``` | ||
| ```diff filename=app/entry.client.tsx | ||
| -import { RemixBrowser } from "@remix-run/react"; | ||
| +import { HydratedRouter } from "react-router/dom"; | ||
| hydrateRoot( | ||
| document, | ||
| <StrictMode> | ||
| - <RemixBrowser /> | ||
| + <HydratedRouter /> | ||
| </StrictMode>, | ||
| ); | ||
| ``` | ||
| ## 9. Update types for `AppLoadContext` | ||
| <docs-info> | ||
| If you were using `remix-serve` you can skip this step. This is only applicable if you were using a custom server in Remix v2. | ||
| </docs-info> | ||
| Since React Router can be used as both a React framework _and_ a stand-alone routing library, the `context` argument for `LoaderFunctionArgs` and `ActionFunctionArgs` is now optional and typed as `any` by default. You can register types for your load context to get type safety for your loaders and actions. | ||
| π **Register types for your load context** | ||
| Before you migrate to the new `Route.LoaderArgs` and `Route.ActionArgs` types, you can temporarily augment `LoaderFunctionArgs` and `ActionFunctionArgs` with your load context type to ease migration. | ||
| ```ts filename=app/env.ts | ||
| declare module "react-router" { | ||
| // Your AppLoadContext used in v2 | ||
| interface AppLoadContext { | ||
| whatever: string; | ||
| } | ||
| // TODO: remove this once we've migrated to `Route.LoaderArgs` instead for our loaders | ||
| interface LoaderFunctionArgs { | ||
| context: AppLoadContext; | ||
| } | ||
| // TODO: remove this once we've migrated to `Route.ActionArgs` instead for our actions | ||
| interface ActionFunctionArgs { | ||
| context: AppLoadContext; | ||
| } | ||
| } | ||
| export {}; // necessary for TS to treat this as a module | ||
| ``` | ||
| <docs-info> | ||
| Using `declare module` to register types is a standard TypeScript technique called [module augmentation][ts-module-augmentation]. | ||
| You can do this in any TypeScript file covered by your `tsconfig.json`'s `include` field, but we recommend a dedicated `env.ts` within your app directory. | ||
| </docs-info> | ||
| π **Use the new types** | ||
| Once you adopt the [new type generation][type-safety], you can remove the `LoaderFunctionArgs`/`ActionFunctionArgs` augmentations and use the `context` argument from [`Route.LoaderArgs`][server-loaders] and [`Route.ActionArgs`][server-actions] instead. | ||
| ```ts filename=app/env.ts | ||
| declare module "react-router" { | ||
| // Your AppLoadContext used in v2 | ||
| interface AppLoadContext { | ||
| whatever: string; | ||
| } | ||
| } | ||
| export {}; // necessary for TS to treat this as a module | ||
| ``` | ||
| ```ts filename=app/routes/my-route.tsx | ||
| import type { Route } from "./+types/my-route"; | ||
| export function loader({ context }: Route.LoaderArgs) {} | ||
| // { whatever: string } ^^^^^^^ | ||
| export function action({ context }: Route.ActionArgs) {} | ||
| // { whatever: string } ^^^^^^^ | ||
| ``` | ||
| Congratulations! You are now on React Router v7. Go ahead and run your application to make sure everything is working as expected. | ||
| [incremental-path-to-react-19]: https://remix.run/blog/incremental-path-to-react-19 | ||
| [v2-future-flags]: https://remix.run/docs/start/future-flags | ||
| [routing]: ../start/framework/routing | ||
| [fs-routing]: ../how-to/file-route-conventions | ||
| [v7-changelog-types]: https://github.com/remix-run/react-router/blob/release-next/CHANGELOG.md#type-safety-improvements | ||
| [server-loaders]: ../start/framework/data-loading#server-data-loading | ||
| [server-actions]: ../start/framework/actions#server-actions | ||
| [ts-module-augmentation]: https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation | ||
| [type-safety]: ../explanation/type-safety | ||
| [codemod]: https://app.codemod.com/registry/remix/2/react-router/upgrade | ||
| [jrestall]: https://github.com/jrestall |
| --- | ||
| title: Upgrading from v6 | ||
| order: 2 | ||
| --- | ||
| # Upgrading from v6 | ||
| <docs-info> | ||
| React Router v7 requires the following minimum versions: | ||
| - `node@20` | ||
| - `react@18` | ||
| - `react-dom@18` | ||
| </docs-info> | ||
| The v7 upgrade has no breaking changes if you have enabled all future flags. These flags allow you to update your app one change at a time. We highly recommend you make a commit after each step and ship it instead of doing everything all at once. | ||
| ## Update to latest v6.x | ||
| First update to the latest minor version of v6.x to have the latest future flags and console warnings. | ||
| π **Update to latest v6** | ||
| ```shellscript nonumber | ||
| npm install react-router-dom@6 | ||
| ``` | ||
| ### v7_relativeSplatPath | ||
| **Background** | ||
| Changes the relative path matching and linking for multi-segment splats paths like `dashboard/*` (vs. just `*`). [View the CHANGELOG](https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#futurev7_relativesplatpath) for more information. | ||
| π **Enable the flag** | ||
| Enabling the flag depends on the type of router: | ||
| ```tsx | ||
| <BrowserRouter | ||
| future={{ | ||
| v7_relativeSplatPath: true, | ||
| }} | ||
| /> | ||
| ``` | ||
| ```tsx | ||
| createBrowserRouter(routes, { | ||
| future: { | ||
| v7_relativeSplatPath: true, | ||
| }, | ||
| }); | ||
| ``` | ||
| **Update your Code** | ||
| If you have any routes with a path + a splat like `<Route path="dashboard/*">` that have relative links like `<Link to="relative">` or `<Link to="../relative">` beneath them, you will need to update your code. | ||
| π **Split the `<Route>` into two** | ||
| Split any multi-segment splat `<Route>` into a parent route with the path and a child route with the splat: | ||
| ```diff | ||
| <Routes> | ||
| <Route path="/" element={<Home />} /> | ||
| - <Route path="dashboard/*" element={<Dashboard />} /> | ||
| + <Route path="dashboard"> | ||
| + <Route path="*" element={<Dashboard />} /> | ||
| + </Route> | ||
| </Routes> | ||
| // or | ||
| createBrowserRouter([ | ||
| { path: "/", element: <Home /> }, | ||
| { | ||
| - path: "dashboard/*", | ||
| - element: <Dashboard />, | ||
| + path: "dashboard", | ||
| + children: [{ path: "*", element: <Dashboard /> }], | ||
| }, | ||
| ]); | ||
| ``` | ||
| π **Update relative links** | ||
| Update any `<Link>` elements within that route tree to include the extra `..` relative segment to continue linking to the same place: | ||
| ```diff | ||
| function Dashboard() { | ||
| return ( | ||
| <div> | ||
| <h2>Dashboard</h2> | ||
| <nav> | ||
| <Link to="/">Dashboard Home</Link> | ||
| - <Link to="team">Team</Link> | ||
| - <Link to="projects">Projects</Link> | ||
| + <Link to="../team">Team</Link> | ||
| + <Link to="../projects">Projects</Link> | ||
| </nav> | ||
| <Routes> | ||
| <Route path="/" element={<DashboardHome />} /> | ||
| <Route path="team" element={<DashboardTeam />} /> | ||
| <Route | ||
| path="projects" | ||
| element={<DashboardProjects />} | ||
| /> | ||
| </Routes> | ||
| </div> | ||
| ); | ||
| } | ||
| ``` | ||
| ### v7_startTransition | ||
| **Background** | ||
| This uses `React.useTransition` instead of `React.useState` for Router state updates. View the [CHANGELOG](https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#futurev7_starttransition) for more information. | ||
| π **Enable the flag** | ||
| ```tsx | ||
| <BrowserRouter | ||
| future={{ | ||
| v7_startTransition: true, | ||
| }} | ||
| /> | ||
| // or | ||
| <RouterProvider | ||
| future={{ | ||
| v7_startTransition: true, | ||
| }} | ||
| /> | ||
| ``` | ||
| π **Update your Code** | ||
| You don't need to update anything unless you are using `React.lazy` _inside_ of a component. | ||
| Using `React.lazy` inside of a component is incompatible with `React.useTransition` (or other code that makes promises inside of components). Move `React.lazy` to the module scope and stop making promises inside of components. This is not a limitation of React Router but rather incorrect usage of React. | ||
| <docs-info>We added a flag to opt-out of `React.startTransition` in v7 so you can use that to upgrade to v7 without adopting React transition-enabled navigations if needed. See the [transition docs][transitions] for more information.</docs-info> | ||
| ### v7_fetcherPersist | ||
| <docs-warning>If you are not using a `<RouterProvider>` you can skip this</docs-warning> | ||
| **Background** | ||
| The fetcher lifecycle is now based on when it returns to an idle state rather than when its owner component unmounts: [View the CHANGELOG](https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#persistence-future-flag-futurev7_fetcherpersist) for more information. | ||
| **Enable the Flag** | ||
| ```tsx | ||
| createBrowserRouter(routes, { | ||
| future: { | ||
| v7_fetcherPersist: true, | ||
| }, | ||
| }); | ||
| ``` | ||
| **Update your Code** | ||
| It's unlikely to affect your app. You may want to check any usage of `useFetchers` as they may persist longer than they did before. Depending on what you're doing, you may render something longer than before. | ||
| ### v7_normalizeFormMethod | ||
| <docs-warning>If you are not using a `<RouterProvider>` you can skip this</docs-warning> | ||
| This normalizes `formMethod` fields as uppercase HTTP methods to align with the `fetch()` behavior. [View the CHANGELOG](https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#futurev7_normalizeformmethod) for more information. | ||
| π **Enable the Flag** | ||
| ```tsx | ||
| createBrowserRouter(routes, { | ||
| future: { | ||
| v7_normalizeFormMethod: true, | ||
| }, | ||
| }); | ||
| ``` | ||
| **Update your Code** | ||
| If any of your code is checking for lowercase HTTP methods, you will need to update it to check for uppercase HTTP methods (or call `toLowerCase()` on it). | ||
| π **Compare `formMethod` to UPPERCASE** | ||
| ```diff | ||
| -useNavigation().formMethod === "post" | ||
| -useFetcher().formMethod === "get"; | ||
| +useNavigation().formMethod === "POST" | ||
| +useFetcher().formMethod === "GET"; | ||
| ``` | ||
| ### v7_partialHydration | ||
| <docs-warning>If you are not using a `<RouterProvider>` you can skip this</docs-warning> | ||
| This enables partial hydration of a data router which is primarily used for SSR frameworks, but it is also useful if you are using `lazy` to load your route modules. It's unlikely you need to worry about this, just turn the flag on. [View the CHANGELOG](https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#partial-hydration) for more information. | ||
| π **Enable the Flag** | ||
| ```tsx | ||
| createBrowserRouter(routes, { | ||
| future: { | ||
| v7_partialHydration: true, | ||
| }, | ||
| }); | ||
| ``` | ||
| **Update your Code** | ||
| With partial hydration, you need to provide a `HydrateFallback` component to render during initial hydration. Additionally, if you were using `fallbackElement` before, you need to remove it as it is now deprecated. In most cases, you will want to reuse the `fallbackElement` as the `HydrateFallback`. | ||
| π **Replace `fallbackElement` with `HydrateFallback`** | ||
| ```diff | ||
| const router = createBrowserRouter( | ||
| [ | ||
| { | ||
| path: "/", | ||
| Component: Layout, | ||
| + HydrateFallback: Fallback, | ||
| // or | ||
| + hydrateFallbackElement: <Fallback />, | ||
| children: [], | ||
| }, | ||
| ], | ||
| ); | ||
| <RouterProvider | ||
| router={router} | ||
| - fallbackElement={<Fallback />} | ||
| /> | ||
| ``` | ||
| ### v7_skipActionErrorRevalidation | ||
| <docs-warning>If you are not using a `createBrowserRouter` you can skip this</docs-warning> | ||
| When this flag is enabled, loaders will no longer revalidate by default after an action throws/returns a `Response` with a `4xx`/`5xx` status code. You may opt-into revalidation in these scenarios via `shouldRevalidate` and the `actionStatus` parameter. | ||
| π **Enable the Flag** | ||
| ```tsx | ||
| createBrowserRouter(routes, { | ||
| future: { | ||
| v7_skipActionErrorRevalidation: true, | ||
| }, | ||
| }); | ||
| ``` | ||
| **Update your Code** | ||
| In most cases, you probably won't have to make changes to your app code. Usually, if an action errors, it's unlikely data was mutated and needs revalidation. If any of your code _does_ mutate data in action error scenarios you have 2 options: | ||
| π **Option 1: Change the `action` to avoid mutations in error scenarios** | ||
| ```js | ||
| // Before | ||
| async function action() { | ||
| await mutateSomeData(); | ||
| if (detectError()) { | ||
| throw new Response(error, { status: 400 }); | ||
| } | ||
| await mutateOtherData(); | ||
| // ... | ||
| } | ||
| // After | ||
| async function action() { | ||
| if (detectError()) { | ||
| throw new Response(error, { status: 400 }); | ||
| } | ||
| // All data is now mutated after validations | ||
| await mutateSomeData(); | ||
| await mutateOtherData(); | ||
| // ... | ||
| } | ||
| ``` | ||
| π **Option 2: Opt-into revalidation via `shouldRevalidate` and `actionStatus`** | ||
| ```js | ||
| async function action() { | ||
| await mutateSomeData(); | ||
| if (detectError()) { | ||
| throw new Response(error, { status: 400 }); | ||
| } | ||
| await mutateOtherData(); | ||
| } | ||
| async function loader() { ... } | ||
| function shouldRevalidate({ actionStatus, defaultShouldRevalidate }) { | ||
| if (actionStatus != null && actionStatus >= 400) { | ||
| // Revalidate this loader when actions return a 4xx/5xx status | ||
| return true; | ||
| } | ||
| return defaultShouldRevalidate; | ||
| } | ||
| ``` | ||
| ## Deprecations | ||
| The `json` and `defer` methods are deprecated in favor of returning raw objects. | ||
| ```diff | ||
| async function loader() { | ||
| - return json({ data }); | ||
| + return { data }; | ||
| ``` | ||
| If you were using `json` to serialize your data to JSON, you can use the native [Response.json()][response-json] method instead. | ||
| ## Upgrade to v7 | ||
| Now that your app is caught up, you can simply update to v7 (theoretically!) without issue. | ||
| π **Install v7** | ||
| ```shellscript nonumber | ||
| npm install react-router-dom@latest | ||
| ``` | ||
| π **Replace react-router-dom with react-router** | ||
| In v7 we no longer need `"react-router-dom"` as the packages have been simplified. You can import everything from `"react-router"`: | ||
| ```shellscript nonumber | ||
| npm uninstall react-router-dom | ||
| npm install react-router@latest | ||
| ``` | ||
| Note you only need `"react-router"` in your package.json. | ||
| π **Update imports** | ||
| Now you should update your imports to use `react-router`: | ||
| ```diff | ||
| -import { useLocation } from "react-router-dom"; | ||
| +import { useLocation } from "react-router"; | ||
| ``` | ||
| Instead of manually updating imports, you can use this command. Make sure your git working tree is clean though so you can revert if it doesn't work as expected. | ||
| ```shellscript nonumber | ||
| find ./path/to/src \( -name "*.tsx" -o -name "*.ts" -o -name "*.js" -o -name "*.jsx" \) -type f -exec sed -i '' 's|from "react-router-dom"|from "react-router"|g' {} + | ||
| ``` | ||
| If you have GNU `sed` installed (most Linux distributions), use this command instead: | ||
| ```shellscript nonumber | ||
| find ./path/to/src \( -name "*.tsx" -o -name "*.ts" -o -name "*.js" -o -name "*.jsx" \) -type f -exec sed -i 's|from "react-router-dom"|from "react-router"|g' {} + | ||
| ``` | ||
| π **Update DOM-specific imports** | ||
| `RouterProvider` and `HydratedRouter` come from a deep import because they depend on `"react-dom"`: | ||
| ```diff | ||
| -import { RouterProvider } from "react-router-dom"; | ||
| +import { RouterProvider } from "react-router/dom"; | ||
| ``` | ||
| Note you should use a top-level import for non-DOM contexts, such as Jest tests: | ||
| ```diff | ||
| -import { RouterProvider } from "react-router-dom"; | ||
| +import { RouterProvider } from "react-router"; | ||
| ``` | ||
| Congratulations, you're now on v7! | ||
| [react-flushsync]: https://react.dev/reference/react-dom/flushSync | ||
| [response-json]: https://developer.mozilla.org/en-US/docs/Web/API/Response/json | ||
| [data-util]: https://api.reactrouter.com/v7/functions/react-router.data.html | ||
| [transitions]: ../explanation/react-transitions |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
2
-33.33%2706796
-0.38%320
-0.31%15
15.38%