diff --git a/.github/workflows/integration-full.yml b/.github/workflows/integration-full.yml index cb1d064ee2..0eb8e062a9 100644 --- a/.github/workflows/integration-full.yml +++ b/.github/workflows/integration-full.yml @@ -31,7 +31,7 @@ jobs: uses: ./.github/workflows/shared-integration.yml with: os: "ubuntu-latest" - node_version: "[20, 22]" + node_version: "[20.18, 22]" browser: '["chromium", "firefox"]' integration-windows: @@ -49,5 +49,5 @@ jobs: uses: ./.github/workflows/shared-integration.yml with: os: "macos-latest" - node_version: "[20, 22]" + node_version: "[20.18, 22]" browser: '["webkit"]' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 64c5125d6d..ca6887c533 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,7 +26,7 @@ jobs: fail-fast: false matrix: node: - - 20 + - 20.18 - 22 runs-on: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index 064a1af494..26e02362e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ We manage release notes in this file instead of the paginated Github Releases Pa Table of Contents - [React Router Releases](#react-router-releases) + - [v7.10.1](#v7101) + - [Patch Changes](#patch-changes) - [v7.10.0](#v7100) - [What's Changed](#whats-changed) - [Stabilized `future.v8_splitRouteModules`](#stabilized-futurev8_splitroutemodules) @@ -20,103 +22,103 @@ We manage release notes in this file instead of the paginated Github Releases Pa - [Stabilized `fetcher.reset()`](#stabilized-fetcherreset) - [Stabilized `DataStrategyMatch.shouldCallHandler()`](#stabilized-datastrategymatchshouldcallhandler) - [Minor Changes](#minor-changes) - - [Patch Changes](#patch-changes) + - [Patch Changes](#patch-changes-1) - [Unstable Changes](#unstable-changes) - [v7.9.6](#v796) - - [Patch Changes](#patch-changes-1) + - [Patch Changes](#patch-changes-2) - [Unstable Changes](#unstable-changes-1) - [v7.9.5](#v795) - [What's Changed](#whats-changed-1) - [Instrumentation (unstable)](#instrumentation-unstable) - - [Patch Changes](#patch-changes-2) + - [Patch Changes](#patch-changes-3) - [Unstable Changes](#unstable-changes-2) - [v7.9.4](#v794) - [What's Changed](#whats-changed-2) - [`useRoute()` (unstable)](#useroute-unstable) - - [Patch Changes](#patch-changes-3) + - [Patch Changes](#patch-changes-4) - [Unstable Changes](#unstable-changes-3) - [v7.9.3](#v793) - - [Patch Changes](#patch-changes-4) + - [Patch Changes](#patch-changes-5) - [v7.9.2](#v792) - [What's Changed](#whats-changed-3) - [RSC Framework Mode (unstable)](#rsc-framework-mode-unstable) - [Fetcher Reset (unstable)](#fetcher-reset-unstable) - - [Patch Changes](#patch-changes-5) + - [Patch Changes](#patch-changes-6) - [Unstable Changes](#unstable-changes-4) - [v7.9.1](#v791) - - [Patch Changes](#patch-changes-6) + - [Patch Changes](#patch-changes-7) - [v7.9.0](#v790) - [What's Changed](#whats-changed-4) - [Stable Middleware and Context APIs](#stable-middleware-and-context-apis) - [Minor Changes](#minor-changes-1) - - [Patch Changes](#patch-changes-7) + - [Patch Changes](#patch-changes-8) - [Unstable Changes](#unstable-changes-5) - [v7.8.2](#v782) - - [Patch Changes](#patch-changes-8) + - [Patch Changes](#patch-changes-9) - [Unstable Changes](#unstable-changes-6) - [v7.8.1](#v781) - - [Patch Changes](#patch-changes-9) + - [Patch Changes](#patch-changes-10) - [Unstable Changes](#unstable-changes-7) - [v7.8.0](#v780) - [What's Changed](#whats-changed-5) - [Consistently named `loaderData` values](#consistently-named-loaderdata-values) - [Improvements/fixes to the middleware APIs (unstable)](#improvementsfixes-to-the-middleware-apis-unstable) - [Minor Changes](#minor-changes-2) - - [Patch Changes](#patch-changes-10) + - [Patch Changes](#patch-changes-11) - [Unstable Changes](#unstable-changes-8) - [Changes by Package](#changes-by-package) - [v7.7.1](#v771) - - [Patch Changes](#patch-changes-11) + - [Patch Changes](#patch-changes-12) - [Unstable Changes](#unstable-changes-9) - [v7.7.0](#v770) - [What's Changed](#whats-changed-6) - [Unstable RSC APIs](#unstable-rsc-apis) - [Minor Changes](#minor-changes-3) - - [Patch Changes](#patch-changes-12) + - [Patch Changes](#patch-changes-13) - [Unstable Changes](#unstable-changes-10) - [Changes by Package](#changes-by-package-1) - [v7.6.3](#v763) - - [Patch Changes](#patch-changes-13) - - [v7.6.2](#v762) - [Patch Changes](#patch-changes-14) - - [v7.6.1](#v761) + - [v7.6.2](#v762) - [Patch Changes](#patch-changes-15) + - [v7.6.1](#v761) + - [Patch Changes](#patch-changes-16) - [Unstable Changes](#unstable-changes-11) - [v7.6.0](#v760) - [What's Changed](#whats-changed-7) - [`routeDiscovery` Config Option](#routediscovery-config-option) - [Automatic Types for Future Flags](#automatic-types-for-future-flags) - [Minor Changes](#minor-changes-4) - - [Patch Changes](#patch-changes-16) + - [Patch Changes](#patch-changes-17) - [Unstable Changes](#unstable-changes-12) - [Changes by Package](#changes-by-package-2) - [v7.5.3](#v753) - - [Patch Changes](#patch-changes-17) + - [Patch Changes](#patch-changes-18) - [v7.5.2](#v752) - [Security Notice](#security-notice) - - [Patch Changes](#patch-changes-18) - - [v7.5.1](#v751) - [Patch Changes](#patch-changes-19) + - [v7.5.1](#v751) + - [Patch Changes](#patch-changes-20) - [Unstable Changes](#unstable-changes-13) - [v7.5.0](#v750) - [What's Changed](#whats-changed-8) - [`route.lazy` Object API](#routelazy-object-api) - [Minor Changes](#minor-changes-5) - - [Patch Changes](#patch-changes-20) + - [Patch Changes](#patch-changes-21) - [Unstable Changes](#unstable-changes-14) - [Changes by Package](#changes-by-package-3) - [v7.4.1](#v741) - [Security Notice](#security-notice-1) - - [Patch Changes](#patch-changes-21) + - [Patch Changes](#patch-changes-22) - [Unstable Changes](#unstable-changes-15) - [v7.4.0](#v740) - [Minor Changes](#minor-changes-6) - - [Patch Changes](#patch-changes-22) + - [Patch Changes](#patch-changes-23) - [Unstable Changes](#unstable-changes-16) - [Changes by Package](#changes-by-package-4) - [v7.3.0](#v730) - [Minor Changes](#minor-changes-7) - - [Patch Changes](#patch-changes-23) + - [Patch Changes](#patch-changes-24) - [Unstable Changes](#unstable-changes-17) - [Client-side `context` (unstable)](#client-side-context-unstable) - [Middleware (unstable)](#middleware-unstable) @@ -129,28 +131,28 @@ We manage release notes in this file instead of the paginated Github Releases Pa - [Prerendering with a SPA Fallback](#prerendering-with-a-spa-fallback) - [Allow a root `loader` in SPA Mode](#allow-a-root-loader-in-spa-mode) - [Minor Changes](#minor-changes-8) - - [Patch Changes](#patch-changes-24) + - [Patch Changes](#patch-changes-25) - [Unstable Changes](#unstable-changes-18) - [Split Route Modules (unstable)](#split-route-modules-unstable) - [Changes by Package](#changes-by-package-6) - [v7.1.5](#v715) - - [Patch Changes](#patch-changes-25) - - [v7.1.4](#v714) - [Patch Changes](#patch-changes-26) - - [v7.1.3](#v713) + - [v7.1.4](#v714) - [Patch Changes](#patch-changes-27) - - [v7.1.2](#v712) + - [v7.1.3](#v713) - [Patch Changes](#patch-changes-28) - - [v7.1.1](#v711) + - [v7.1.2](#v712) - [Patch Changes](#patch-changes-29) + - [v7.1.1](#v711) + - [Patch Changes](#patch-changes-30) - [v7.1.0](#v710) - [Minor Changes](#minor-changes-9) - - [Patch Changes](#patch-changes-30) + - [Patch Changes](#patch-changes-31) - [Changes by Package](#changes-by-package-7) - [v7.0.2](#v702) - - [Patch Changes](#patch-changes-31) - - [v7.0.1](#v701) - [Patch Changes](#patch-changes-32) + - [v7.0.1](#v701) + - [Patch Changes](#patch-changes-33) - [v7.0.0](#v700) - [Breaking Changes](#breaking-changes) - [Package Restructuring](#package-restructuring) @@ -167,203 +169,203 @@ We manage release notes in this file instead of the paginated Github Releases Pa - [Major Changes (`react-router`)](#major-changes-react-router) - [Major Changes (`@react-router/*`)](#major-changes-react-router-1) - [Minor Changes](#minor-changes-10) - - [Patch Changes](#patch-changes-33) + - [Patch Changes](#patch-changes-34) - [Changes by Package](#changes-by-package-8) - [React Router v6 Releases](#react-router-v6-releases) - [v6.30.2](#v6302) - - [Patch Changes](#patch-changes-34) - - [v6.30.1](#v6301) - [Patch Changes](#patch-changes-35) + - [v6.30.1](#v6301) + - [Patch Changes](#patch-changes-36) - [v6.30.0](#v6300) - [Minor Changes](#minor-changes-11) - - [Patch Changes](#patch-changes-36) + - [Patch Changes](#patch-changes-37) - [v6.29.0](#v6290) - [Minor Changes](#minor-changes-12) - - [Patch Changes](#patch-changes-37) - - [v6.28.2](#v6282) - [Patch Changes](#patch-changes-38) - - [v6.28.1](#v6281) + - [v6.28.2](#v6282) - [Patch Changes](#patch-changes-39) + - [v6.28.1](#v6281) + - [Patch Changes](#patch-changes-40) - [v6.28.0](#v6280) - [What's Changed](#whats-changed-10) - [Minor Changes](#minor-changes-13) - - [Patch Changes](#patch-changes-40) + - [Patch Changes](#patch-changes-41) - [v6.27.0](#v6270) - [What's Changed](#whats-changed-11) - [Stabilized APIs](#stabilized-apis) - [Minor Changes](#minor-changes-14) - - [Patch Changes](#patch-changes-41) - - [v6.26.2](#v6262) - [Patch Changes](#patch-changes-42) - - [v6.26.1](#v6261) + - [v6.26.2](#v6262) - [Patch Changes](#patch-changes-43) + - [v6.26.1](#v6261) + - [Patch Changes](#patch-changes-44) - [v6.26.0](#v6260) - [Minor Changes](#minor-changes-15) - - [Patch Changes](#patch-changes-44) - - [v6.25.1](#v6251) - [Patch Changes](#patch-changes-45) + - [v6.25.1](#v6251) + - [Patch Changes](#patch-changes-46) - [v6.25.0](#v6250) - [What's Changed](#whats-changed-12) - [Stabilized `v7_skipActionErrorRevalidation`](#stabilized-v7_skipactionerrorrevalidation) - [Minor Changes](#minor-changes-16) - - [Patch Changes](#patch-changes-46) - - [v6.24.1](#v6241) - [Patch Changes](#patch-changes-47) + - [v6.24.1](#v6241) + - [Patch Changes](#patch-changes-48) - [v6.24.0](#v6240) - [What's Changed](#whats-changed-13) - [Lazy Route Discovery (a.k.a. "Fog of War")](#lazy-route-discovery-aka-fog-of-war) - [Minor Changes](#minor-changes-17) - - [Patch Changes](#patch-changes-48) - - [v6.23.1](#v6231) - [Patch Changes](#patch-changes-49) + - [v6.23.1](#v6231) + - [Patch Changes](#patch-changes-50) - [v6.23.0](#v6230) - [What's Changed](#whats-changed-14) - [Data Strategy (unstable)](#data-strategy-unstable) - [Skip Action Error Revalidation (unstable)](#skip-action-error-revalidation-unstable) - [Minor Changes](#minor-changes-18) - [v6.22.3](#v6223) - - [Patch Changes](#patch-changes-50) - - [v6.22.2](#v6222) - [Patch Changes](#patch-changes-51) - - [v6.22.1](#v6221) + - [v6.22.2](#v6222) - [Patch Changes](#patch-changes-52) + - [v6.22.1](#v6221) + - [Patch Changes](#patch-changes-53) - [v6.22.0](#v6220) - [What's Changed](#whats-changed-15) - [Core Web Vitals Technology Report Flag](#core-web-vitals-technology-report-flag) - [Minor Changes](#minor-changes-19) - - [Patch Changes](#patch-changes-53) - - [v6.21.3](#v6213) - [Patch Changes](#patch-changes-54) - - [v6.21.2](#v6212) + - [v6.21.3](#v6213) - [Patch Changes](#patch-changes-55) - - [v6.21.1](#v6211) + - [v6.21.2](#v6212) - [Patch Changes](#patch-changes-56) + - [v6.21.1](#v6211) + - [Patch Changes](#patch-changes-57) - [v6.21.0](#v6210) - [What's Changed](#whats-changed-16) - [`future.v7_relativeSplatPath`](#futurev7_relativesplatpath) - [Partial Hydration](#partial-hydration) - [Minor Changes](#minor-changes-20) - - [Patch Changes](#patch-changes-57) - - [v6.20.1](#v6201) - [Patch Changes](#patch-changes-58) + - [v6.20.1](#v6201) + - [Patch Changes](#patch-changes-59) - [v6.20.0](#v6200) - [Minor Changes](#minor-changes-21) - - [Patch Changes](#patch-changes-59) + - [Patch Changes](#patch-changes-60) - [v6.19.0](#v6190) - [What's Changed](#whats-changed-17) - [`unstable_flushSync` API](#unstable_flushsync-api) - [Minor Changes](#minor-changes-22) - - [Patch Changes](#patch-changes-60) + - [Patch Changes](#patch-changes-61) - [v6.18.0](#v6180) - [What's Changed](#whats-changed-18) - [New Fetcher APIs](#new-fetcher-apis) - [Persistence Future Flag (`future.v7_fetcherPersist`)](#persistence-future-flag-futurev7_fetcherpersist) - [Minor Changes](#minor-changes-23) - - [Patch Changes](#patch-changes-61) + - [Patch Changes](#patch-changes-62) - [v6.17.0](#v6170) - [What's Changed](#whats-changed-19) - [View Transitions 🚀](#view-transitions-) - [Minor Changes](#minor-changes-24) - - [Patch Changes](#patch-changes-62) + - [Patch Changes](#patch-changes-63) - [v6.16.0](#v6160) - [Minor Changes](#minor-changes-25) - - [Patch Changes](#patch-changes-63) + - [Patch Changes](#patch-changes-64) - [v6.15.0](#v6150) - [Minor Changes](#minor-changes-26) - - [Patch Changes](#patch-changes-64) - - [v6.14.2](#v6142) - [Patch Changes](#patch-changes-65) - - [v6.14.1](#v6141) + - [v6.14.2](#v6142) - [Patch Changes](#patch-changes-66) + - [v6.14.1](#v6141) + - [Patch Changes](#patch-changes-67) - [v6.14.0](#v6140) - [What's Changed](#whats-changed-20) - [JSON/Text Submissions](#jsontext-submissions) - [Minor Changes](#minor-changes-27) - - [Patch Changes](#patch-changes-67) + - [Patch Changes](#patch-changes-68) - [v6.13.0](#v6130) - [What's Changed](#whats-changed-21) - [`future.v7_startTransition`](#futurev7_starttransition) - [Minor Changes](#minor-changes-28) - - [Patch Changes](#patch-changes-68) - - [v6.12.1](#v6121) - [Patch Changes](#patch-changes-69) + - [v6.12.1](#v6121) + - [Patch Changes](#patch-changes-70) - [v6.12.0](#v6120) - [What's Changed](#whats-changed-22) - [`React.startTransition` support](#reactstarttransition-support) - [Minor Changes](#minor-changes-29) - - [Patch Changes](#patch-changes-70) - - [v6.11.2](#v6112) - [Patch Changes](#patch-changes-71) - - [v6.11.1](#v6111) + - [v6.11.2](#v6112) - [Patch Changes](#patch-changes-72) + - [v6.11.1](#v6111) + - [Patch Changes](#patch-changes-73) - [v6.11.0](#v6110) - [Minor Changes](#minor-changes-30) - - [Patch Changes](#patch-changes-73) + - [Patch Changes](#patch-changes-74) - [v6.10.0](#v6100) - [What's Changed](#whats-changed-23) - [Minor Changes](#minor-changes-31) - [`future.v7_normalizeFormMethod`](#futurev7_normalizeformmethod) - - [Patch Changes](#patch-changes-74) + - [Patch Changes](#patch-changes-75) - [v6.9.0](#v690) - [What's Changed](#whats-changed-24) - [`Component`/`ErrorBoundary` route properties](#componenterrorboundary-route-properties) - [Introducing Lazy Route Modules](#introducing-lazy-route-modules) - [Minor Changes](#minor-changes-32) - - [Patch Changes](#patch-changes-75) - - [v6.8.2](#v682) - [Patch Changes](#patch-changes-76) - - [v6.8.1](#v681) + - [v6.8.2](#v682) - [Patch Changes](#patch-changes-77) + - [v6.8.1](#v681) + - [Patch Changes](#patch-changes-78) - [v6.8.0](#v680) - [Minor Changes](#minor-changes-33) - - [Patch Changes](#patch-changes-78) + - [Patch Changes](#patch-changes-79) - [v6.7.0](#v670) - [Minor Changes](#minor-changes-34) - - [Patch Changes](#patch-changes-79) - - [v6.6.2](#v662) - [Patch Changes](#patch-changes-80) - - [v6.6.1](#v661) + - [v6.6.2](#v662) - [Patch Changes](#patch-changes-81) + - [v6.6.1](#v661) + - [Patch Changes](#patch-changes-82) - [v6.6.0](#v660) - [What's Changed](#whats-changed-25) - [Minor Changes](#minor-changes-35) - - [Patch Changes](#patch-changes-82) + - [Patch Changes](#patch-changes-83) - [v6.5.0](#v650) - [What's Changed](#whats-changed-26) - [Minor Changes](#minor-changes-36) - - [Patch Changes](#patch-changes-83) - - [v6.4.5](#v645) - [Patch Changes](#patch-changes-84) - - [v6.4.4](#v644) + - [v6.4.5](#v645) - [Patch Changes](#patch-changes-85) - - [v6.4.3](#v643) + - [v6.4.4](#v644) - [Patch Changes](#patch-changes-86) - - [v6.4.2](#v642) + - [v6.4.3](#v643) - [Patch Changes](#patch-changes-87) - - [v6.4.1](#v641) + - [v6.4.2](#v642) - [Patch Changes](#patch-changes-88) + - [v6.4.1](#v641) + - [Patch Changes](#patch-changes-89) - [v6.4.0](#v640) - [What's Changed](#whats-changed-27) - [Remix Data APIs](#remix-data-apis) - - [Patch Changes](#patch-changes-89) + - [Patch Changes](#patch-changes-90) - [v6.3.0](#v630) - [Minor Changes](#minor-changes-37) - [v6.2.2](#v622) - - [Patch Changes](#patch-changes-90) - - [v6.2.1](#v621) - [Patch Changes](#patch-changes-91) + - [v6.2.1](#v621) + - [Patch Changes](#patch-changes-92) - [v6.2.0](#v620) - [Minor Changes](#minor-changes-38) - - [Patch Changes](#patch-changes-92) - - [v6.1.1](#v611) - [Patch Changes](#patch-changes-93) + - [v6.1.1](#v611) + - [Patch Changes](#patch-changes-94) - [v6.1.0](#v610) - [Minor Changes](#minor-changes-39) - - [Patch Changes](#patch-changes-94) - - [v6.0.2](#v602) - [Patch Changes](#patch-changes-95) - - [v6.0.1](#v601) + - [v6.0.2](#v602) - [Patch Changes](#patch-changes-96) + - [v6.0.1](#v601) + - [Patch Changes](#patch-changes-97) - [v6.0.0](#v600) @@ -391,6 +393,18 @@ Date: YYYY-MM-DD **Full Changelog**: [`v7.X.Y...v7.X.Y`](https://github.com/remix-run/react-router/compare/react-router@7.X.Y...react-router@7.X.Y) --> +## v7.10.1 + +Date: 2025-12-04 + +### Patch Changes + +- `react-router` - Update the `useOptimistic` stub we provide for React 18 users to use a stable setter function to avoid potential `useEffect` loops - specifically when using `` ([#14628](https://github.com/remix-run/react-router/pull/14628)) +- `@react-router/dev` - Import ESM package `pkg-types` with a dynamic `import()` to fix issues on Node 20.18 ([#14624](https://github.com/remix-run/react-router/pull/14624)) +- `@react-router/dev` - Update `valibot` dependency to `^1.2.0` to address [GHSA-vqpr-j7v3-hqw9](https://github.com/advisories/GHSA-vqpr-j7v3-hqw9) ([#14608](https://github.com/remix-run/react-router/pull/14608)) + +**Full Changelog**: [`v7.10.0...v7.10.1`](https://github.com/remix-run/react-router/compare/react-router@7.10.0...react-router@7.10.1) + ## v7.10.0 Date: 2025-12-02 diff --git a/contributors.yml b/contributors.yml index c0eb22e16b..64f04cec93 100644 --- a/contributors.yml +++ b/contributors.yml @@ -147,6 +147,7 @@ - haivuw - hampelm - harshmangalam +- harucn - HelpMe-Pls - HenriqueLimas - hernanif1 diff --git a/docs/api/components/Form.md b/docs/api/components/Form.md index 787906db7c..67d7a9e281 100644 --- a/docs/api/components/Form.md +++ b/docs/api/components/Form.md @@ -62,17 +62,17 @@ closest route in context. ### discover -Defines the link discovery behavior. See [`DiscoverBehavior`](https://api.reactrouter.com/v7/types/react_router.DiscoverBehavior.html). +Defines the form [lazy route discovery](../../explanation/lazy-route-discovery) behavior. + +- **render** — default, discover the route when the form renders +- **none** — don't eagerly discover, only discover if the form is submitted ```tsx - // default ("render") - - +
// default ("render") + + ``` -- **render** — default, discover the route when the link renders -- **none** — don't eagerly discover, only discover if the link is clicked - ### encType The encoding type to use for the form submission. diff --git a/docs/api/components/Link.md b/docs/api/components/Link.md index ca8ea63f4a..db4ae3033e 100644 --- a/docs/api/components/Link.md +++ b/docs/api/components/Link.md @@ -45,7 +45,10 @@ import { Link } from "react-router"; [modes: framework] -Defines the link discovery behavior +Defines the link [lazy route discovery](../../explanation/lazy-route-discovery) behavior. + +- **render** — default, discover the route when the link renders +- **none** — don't eagerly discover, only discover if the link is clicked ```tsx // default ("render") @@ -53,9 +56,6 @@ Defines the link discovery behavior ``` -- **render** — default, discover the route when the link renders -- **none** — don't eagerly discover, only discover if the link is clicked - ### prefetch [modes: framework] diff --git a/docs/api/components/NavLink.md b/docs/api/components/NavLink.md index 34ca860662..8a763dbcfd 100644 --- a/docs/api/components/NavLink.md +++ b/docs/api/components/NavLink.md @@ -109,7 +109,10 @@ returns the `className`: [modes: framework] -Defines the link discovery behavior +Defines the link [lazy route discovery](../../explanation/lazy-route-discovery) behavior. + +- **render** — default, discover the route when the link renders +- **none** — don't eagerly discover, only discover if the link is clicked ```tsx // default ("render") @@ -117,9 +120,6 @@ Defines the link discovery behavior ``` -- **render** — default, discover the route when the link renders -- **none** — don't eagerly discover, only discover if the link is clicked - ### end [modes: framework, data, declarative] diff --git a/docs/api/data-routers/createBrowserRouter.md b/docs/api/data-routers/createBrowserRouter.md index ff0ca8c1bd..185f482fe2 100644 --- a/docs/api/data-routers/createBrowserRouter.md +++ b/docs/api/data-routers/createBrowserRouter.md @@ -47,189 +47,32 @@ Basename path for the application. ### opts.dataStrategy -Override the default data strategy of running loaders in parallel. -See [`DataStrategyFunction`](https://api.reactrouter.com/v7/interfaces/react_router.DataStrategyFunction.html). - -This is a low-level API intended for advanced use-cases. This -overrides React Router's internal handling of -[`action`](../../start/data/route-object#action)/[`loader`](../../start/data/route-object#loader) -execution, and if done incorrectly will break your app code. Please use -with caution and perform the appropriate testing. - -By default, React Router is opinionated about how your data is loaded/submitted - -and most notably, executes all of your [`loader`](../../start/data/route-object#loader)s -in parallel for optimal data fetching. While we think this is the right -behavior for most use-cases, we realize that there is no "one size fits all" -solution when it comes to data fetching for the wide landscape of -application requirements. - -The `dataStrategy` option gives you full control over how your [`action`](../../start/data/route-object#action)s -and [`loader`](../../start/data/route-object#loader)s are executed and lays -the foundation to build in more advanced APIs such as middleware, context, -and caching layers. Over time, we expect that we'll leverage this API -internally to bring more first class APIs to React Router, but until then -(and beyond), this is your way to add more advanced functionality for your -application's data needs. - -The `dataStrategy` function should return a key/value-object of -`routeId` -> [`DataStrategyResult`](https://api.reactrouter.com/v7/interfaces/react_router.DataStrategyResult.html) and should include entries for any -routes where a handler was executed. A `DataStrategyResult` indicates if -the handler was successful or not based on the `DataStrategyResult.type` -field. If the returned `DataStrategyResult.result` is a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response), -React Router will unwrap it for you (via [`res.json`](https://developer.mozilla.org/en-US/docs/Web/API/Response/json) -or [`res.text`](https://developer.mozilla.org/en-US/docs/Web/API/Response/text)). -If you need to do custom decoding of a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) -but want to preserve the status code, you can use the `data` utility to -return your decoded data along with a `ResponseInit`. - -
-Example dataStrategy Use Cases - -**Adding logging** - -In the simplest case, let's look at hooking into this API to add some logging -for when our route [`action`](../../start/data/route-object#action)s/[`loader`](../../start/data/route-object#loader)s -execute: +Override the default data strategy of running loaders in parallel - +see the [docs](../../how-to/data-strategy) for more information. ```tsx let router = createBrowserRouter(routes, { - async dataStrategy({ matches, request }) { - const matchesToLoad = matches.filter((m) => m.shouldLoad); - const results: Record = {}; - await Promise.all( - matchesToLoad.map(async (match) => { - console.log(`Processing ${match.route.id}`); - results[match.route.id] = await match.resolve();; - }) + async dataStrategy({ + matches, + request, + runClientMiddleware, + }) { + const matchesToLoad = matches.filter((m) => + m.shouldCallHandler(), ); - return results; - }, -}); -``` - -**Middleware** -Let's define a middleware on each route via [`handle`](../../start/data/route-object#handle) -and call middleware sequentially first, then call all -[`loader`](../../start/data/route-object#loader)s in parallel - providing -any data made available via the middleware: - -```ts -const routes = [ - { - id: "parent", - path: "/parent", - loader({ request }, context) { - // ... - }, - handle: { - async middleware({ request }, context) { - context.parent = "PARENT MIDDLEWARE"; - }, - }, - children: [ - { - id: "child", - path: "child", - loader({ request }, context) { - // ... - }, - handle: { - async middleware({ request }, context) { - context.child = "CHILD MIDDLEWARE"; - }, - }, - }, - ], - }, -]; - -let router = createBrowserRouter(routes, { - async dataStrategy({ matches, params, request }) { - // Run middleware sequentially and let them add data to `context` - let context = {}; - for (const match of matches) { - if (match.route.handle?.middleware) { - await match.route.handle.middleware( - { request, params }, - context - ); - } - } - - // Run loaders in parallel with the `context` value - let matchesToLoad = matches.filter((m) => m.shouldLoad); - let results = await Promise.all( - matchesToLoad.map((match, i) => - match.resolve((handler) => { - // Whatever you pass to `handler` will be passed as the 2nd parameter - // to your loader/action - return handler(context); - }) - ) - ); - return results.reduce( - (acc, result, i) => - Object.assign(acc, { - [matchesToLoad[i].route.id]: result, + const results: Record = {}; + await runClientMiddleware(() => + Promise.all( + matchesToLoad.map(async (match) => { + results[match.route.id] = await match.resolve(); }), - {} + ), ); - }, -}); -``` - -**Custom Handler** - -It's also possible you don't even want to define a [`loader`](../../start/data/route-object#loader) -implementation at the route level. Maybe you want to just determine the -routes and issue a single GraphQL request for all of your data? You can do -that by setting your `route.loader=true` so it qualifies as "having a -loader", and then store GQL fragments on `route.handle`: - -```ts -const routes = [ - { - id: "parent", - path: "/parent", - loader: true, - handle: { - gql: gql` - fragment Parent on Whatever { - parentField - } - `, - }, - children: [ - { - id: "child", - path: "child", - loader: true, - handle: { - gql: gql` - fragment Child on Whatever { - childField - } - `, - }, - }, - ], - }, -]; - -let router = createBrowserRouter(routes, { - async dataStrategy({ matches, params, request }) { - // Compose route fragments into a single GQL payload - let gql = getFragmentsFromRouteHandles(matches); - let data = await fetchGql(gql); - // Parse results back out into individual route level `DataStrategyResult`'s - // keyed by `routeId` - let results = parseResultsFromGql(data); return results; }, }); ``` -
### opts.future @@ -336,7 +179,7 @@ individual routes prior to router initialization (and on any subsequently added routes via `route.lazy` or `patchRoutesOnNavigation`). This is mostly useful for observability such as wrapping navigations, fetches, as well as route loaders/actions/middlewares with logging and/or performance -tracing. +tracing. See the [docs](../../how-to/instrumentation) for more information. ```tsx let router = createBrowserRouter(routes, { diff --git a/docs/api/data-routers/createHashRouter.md b/docs/api/data-routers/createHashRouter.md index 427b74a9ec..d95832da07 100644 --- a/docs/api/data-routers/createHashRouter.md +++ b/docs/api/data-routers/createHashRouter.md @@ -149,7 +149,7 @@ individual routes prior to router initialization (and on any subsequently added routes via `route.lazy` or `patchRoutesOnNavigation`). This is mostly useful for observability such as wrapping navigations, fetches, as well as route loaders/actions/middlewares with logging and/or performance -tracing. +tracing. See the [docs](../../how-to/instrumentation) for more information. ```tsx let router = createBrowserRouter(routes, { @@ -193,189 +193,32 @@ async function logExecution(label: string, impl: () => Promise) { ### opts.dataStrategy -Override the default data strategy of running loaders in parallel. -See [`DataStrategyFunction`](https://api.reactrouter.com/v7/interfaces/react_router.DataStrategyFunction.html). - -This is a low-level API intended for advanced use-cases. This -overrides React Router's internal handling of -[`action`](../../start/data/route-object#action)/[`loader`](../../start/data/route-object#loader) -execution, and if done incorrectly will break your app code. Please use -with caution and perform the appropriate testing. - -By default, React Router is opinionated about how your data is loaded/submitted - -and most notably, executes all of your [`loader`](../../start/data/route-object#loader)s -in parallel for optimal data fetching. While we think this is the right -behavior for most use-cases, we realize that there is no "one size fits all" -solution when it comes to data fetching for the wide landscape of -application requirements. - -The `dataStrategy` option gives you full control over how your [`action`](../../start/data/route-object#action)s -and [`loader`](../../start/data/route-object#loader)s are executed and lays -the foundation to build in more advanced APIs such as middleware, context, -and caching layers. Over time, we expect that we'll leverage this API -internally to bring more first class APIs to React Router, but until then -(and beyond), this is your way to add more advanced functionality for your -application's data needs. - -The `dataStrategy` function should return a key/value-object of -`routeId` -> [`DataStrategyResult`](https://api.reactrouter.com/v7/interfaces/react_router.DataStrategyResult.html) and should include entries for any -routes where a handler was executed. A `DataStrategyResult` indicates if -the handler was successful or not based on the `DataStrategyResult.type` -field. If the returned `DataStrategyResult.result` is a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response), -React Router will unwrap it for you (via [`res.json`](https://developer.mozilla.org/en-US/docs/Web/API/Response/json) -or [`res.text`](https://developer.mozilla.org/en-US/docs/Web/API/Response/text)). -If you need to do custom decoding of a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) -but want to preserve the status code, you can use the `data` utility to -return your decoded data along with a `ResponseInit`. - -
-Example dataStrategy Use Cases - -**Adding logging** - -In the simplest case, let's look at hooking into this API to add some logging -for when our route [`action`](../../start/data/route-object#action)s/[`loader`](../../start/data/route-object#loader)s -execute: +Override the default data strategy of running loaders in parallel - +see the [docs](../../how-to/data-strategy) for more information. ```tsx let router = createBrowserRouter(routes, { - async dataStrategy({ matches, request }) { - const matchesToLoad = matches.filter((m) => m.shouldLoad); - const results: Record = {}; - await Promise.all( - matchesToLoad.map(async (match) => { - console.log(`Processing ${match.route.id}`); - results[match.route.id] = await match.resolve();; - }) + async dataStrategy({ + matches, + request, + runClientMiddleware, + }) { + const matchesToLoad = matches.filter((m) => + m.shouldCallHandler(), ); - return results; - }, -}); -``` - -**Middleware** -Let's define a middleware on each route via [`handle`](../../start/data/route-object#handle) -and call middleware sequentially first, then call all -[`loader`](../../start/data/route-object#loader)s in parallel - providing -any data made available via the middleware: - -```ts -const routes = [ - { - id: "parent", - path: "/parent", - loader({ request }, context) { - // ... - }, - handle: { - async middleware({ request }, context) { - context.parent = "PARENT MIDDLEWARE"; - }, - }, - children: [ - { - id: "child", - path: "child", - loader({ request }, context) { - // ... - }, - handle: { - async middleware({ request }, context) { - context.child = "CHILD MIDDLEWARE"; - }, - }, - }, - ], - }, -]; - -let router = createBrowserRouter(routes, { - async dataStrategy({ matches, params, request }) { - // Run middleware sequentially and let them add data to `context` - let context = {}; - for (const match of matches) { - if (match.route.handle?.middleware) { - await match.route.handle.middleware( - { request, params }, - context - ); - } - } - - // Run loaders in parallel with the `context` value - let matchesToLoad = matches.filter((m) => m.shouldLoad); - let results = await Promise.all( - matchesToLoad.map((match, i) => - match.resolve((handler) => { - // Whatever you pass to `handler` will be passed as the 2nd parameter - // to your loader/action - return handler(context); - }) - ) - ); - return results.reduce( - (acc, result, i) => - Object.assign(acc, { - [matchesToLoad[i].route.id]: result, + const results: Record = {}; + await runClientMiddleware(() => + Promise.all( + matchesToLoad.map(async (match) => { + results[match.route.id] = await match.resolve(); }), - {} + ), ); - }, -}); -``` - -**Custom Handler** - -It's also possible you don't even want to define a [`loader`](../../start/data/route-object#loader) -implementation at the route level. Maybe you want to just determine the -routes and issue a single GraphQL request for all of your data? You can do -that by setting your `route.loader=true` so it qualifies as "having a -loader", and then store GQL fragments on `route.handle`: - -```ts -const routes = [ - { - id: "parent", - path: "/parent", - loader: true, - handle: { - gql: gql` - fragment Parent on Whatever { - parentField - } - `, - }, - children: [ - { - id: "child", - path: "child", - loader: true, - handle: { - gql: gql` - fragment Child on Whatever { - childField - } - `, - }, - }, - ], - }, -]; - -let router = createBrowserRouter(routes, { - async dataStrategy({ matches, params, request }) { - // Compose route fragments into a single GQL payload - let gql = getFragmentsFromRouteHandles(matches); - let data = await fetchGql(gql); - // Parse results back out into individual route level `DataStrategyResult`'s - // keyed by `routeId` - let results = parseResultsFromGql(data); return results; }, }); ``` -
### opts.patchRoutesOnNavigation diff --git a/docs/api/data-routers/createMemoryRouter.md b/docs/api/data-routers/createMemoryRouter.md index 28b2e37c48..c8bccee7d4 100644 --- a/docs/api/data-routers/createMemoryRouter.md +++ b/docs/api/data-routers/createMemoryRouter.md @@ -47,8 +47,32 @@ Basename path for the application. ### opts.dataStrategy -Override the default data strategy of loading in parallel. -Only intended for advanced usage. +Override the default data strategy of running loaders in parallel - +see the [docs](../../how-to/data-strategy) for more information. + +```tsx +let router = createBrowserRouter(routes, { + async dataStrategy({ + matches, + request, + runClientMiddleware, + }) { + const matchesToLoad = matches.filter((m) => + m.shouldCallHandler(), + ); + + const results: Record = {}; + await runClientMiddleware(() => + Promise.all( + matchesToLoad.map(async (match) => { + results[match.route.id] = await match.resolve(); + }), + ), + ); + return results; + }, +}); +``` ### opts.future @@ -82,7 +106,7 @@ individual routes prior to router initialization (and on any subsequently added routes via `route.lazy` or `patchRoutesOnNavigation`). This is mostly useful for observability such as wrapping navigations, fetches, as well as route loaders/actions/middlewares with logging and/or performance -tracing. +tracing. See the [docs](../../how-to/instrumentation) for more information. ```tsx let router = createBrowserRouter(routes, { diff --git a/docs/api/hooks/useNavigate.md b/docs/api/hooks/useNavigate.md index 58de33ba20..ffc0cf2a2d 100644 --- a/docs/api/hooks/useNavigate.md +++ b/docs/api/hooks/useNavigate.md @@ -78,14 +78,12 @@ navigate("/some/route?search=param"); All properties are optional. ```tsx -navigate( - { - pathname: "/some/route", - search: "?search=param", - hash: "#hash", - }, - { state: { some: "state" } } -); +navigate({ + pathname: "/some/route", + search: "?search=param", + hash: "#hash", + state: { some: "state" }, +}); ``` If you use `state`, that will be available on the [`Location`](https://api.reactrouter.com/v7/interfaces/react_router.Location.html) object on diff --git a/packages/create-react-router/CHANGELOG.md b/packages/create-react-router/CHANGELOG.md index b1a09daa0e..c7e77928c5 100644 --- a/packages/create-react-router/CHANGELOG.md +++ b/packages/create-react-router/CHANGELOG.md @@ -1,5 +1,9 @@ # `create-react-router` +## 7.10.1 + +_No changes_ + ## 7.10.0 _No changes_ diff --git a/packages/create-react-router/package.json b/packages/create-react-router/package.json index da5a573821..36ad0775d1 100644 --- a/packages/create-react-router/package.json +++ b/packages/create-react-router/package.json @@ -1,6 +1,6 @@ { "name": "create-react-router", - "version": "7.10.0", + "version": "7.10.1", "description": "Create a new React Router app", "homepage": "https://reactrouter.com", "bugs": { diff --git a/packages/react-router-architect/CHANGELOG.md b/packages/react-router-architect/CHANGELOG.md index 3bae066134..79ee31da68 100644 --- a/packages/react-router-architect/CHANGELOG.md +++ b/packages/react-router-architect/CHANGELOG.md @@ -1,5 +1,13 @@ # `@react-router/architect` +## 7.10.1 + +### Patch Changes + +- Updated dependencies: + - `react-router@7.10.1` + - `@react-router/node@7.10.1` + ## 7.10.0 ### Patch Changes diff --git a/packages/react-router-architect/package.json b/packages/react-router-architect/package.json index 0862e92715..f1fad143e1 100644 --- a/packages/react-router-architect/package.json +++ b/packages/react-router-architect/package.json @@ -1,6 +1,6 @@ { "name": "@react-router/architect", - "version": "7.10.0", + "version": "7.10.1", "description": "Architect server request handler for React Router", "bugs": { "url": "https://github.com/remix-run/react-router/issues" diff --git a/packages/react-router-cloudflare/CHANGELOG.md b/packages/react-router-cloudflare/CHANGELOG.md index ade7635d77..8862fa823e 100644 --- a/packages/react-router-cloudflare/CHANGELOG.md +++ b/packages/react-router-cloudflare/CHANGELOG.md @@ -1,5 +1,12 @@ # `@react-router/cloudflare` +## 7.10.1 + +### Patch Changes + +- Updated dependencies: + - `react-router@7.10.1` + ## 7.10.0 ### Patch Changes diff --git a/packages/react-router-cloudflare/package.json b/packages/react-router-cloudflare/package.json index c1161a604b..41e8b707ed 100644 --- a/packages/react-router-cloudflare/package.json +++ b/packages/react-router-cloudflare/package.json @@ -1,6 +1,6 @@ { "name": "@react-router/cloudflare", - "version": "7.10.0", + "version": "7.10.1", "description": "Cloudflare platform abstractions for React Router", "bugs": { "url": "https://github.com/remix-run/react-router/issues" diff --git a/packages/react-router-dev/CHANGELOG.md b/packages/react-router-dev/CHANGELOG.md index ffc9c3f957..b99d47b8e6 100644 --- a/packages/react-router-dev/CHANGELOG.md +++ b/packages/react-router-dev/CHANGELOG.md @@ -1,5 +1,16 @@ # `@react-router/dev` +## 7.10.1 + +### Patch Changes + +- Import ESM package `pkg-types` with a dynamic `import()` to fix issues on Node 20.18 ([#14624](https://github.com/remix-run/react-router/pull/14624)) +- Update `valibot` dependency to `^1.2.0` to address [GHSA-vqpr-j7v3-hqw9](https://github.com/advisories/GHSA-vqpr-j7v3-hqw9) ([#14608](https://github.com/remix-run/react-router/pull/14608)) +- Updated dependencies: + - `react-router@7.10.1` + - `@react-router/node@7.10.1` + - `@react-router/serve@7.10.1` + ## 7.10.0 ### Minor Changes diff --git a/packages/react-router-dev/cli/commands.ts b/packages/react-router-dev/cli/commands.ts index 42c3d604f1..3e4d615932 100644 --- a/packages/react-router-dev/cli/commands.ts +++ b/packages/react-router-dev/cli/commands.ts @@ -3,7 +3,6 @@ import { readFile, writeFile } from "node:fs/promises"; import * as path from "node:path"; import exitHook from "exit-hook"; import colors from "picocolors"; -import { readPackageJSON } from "pkg-types"; // Workaround for "ERR_REQUIRE_CYCLE_MODULE" in Node 22.10.0+ import "react-router"; @@ -138,6 +137,8 @@ export async function generateEntry( return; } + // TODO(v8): Remove - only required for Node 20.18 and below + let { readPackageJSON } = await import("pkg-types"); let pkgJson = await readPackageJSON(rootDirectory); let deps = pkgJson.dependencies ?? {}; diff --git a/packages/react-router-dev/config/config.ts b/packages/react-router-dev/config/config.ts index 9edaa01175..e69c89960f 100644 --- a/packages/react-router-dev/config/config.ts +++ b/packages/react-router-dev/config/config.ts @@ -8,7 +8,6 @@ import chokidar, { type EmitArgs as ChokidarEmitArgs, } from "chokidar"; import colors from "picocolors"; -import { readPackageJSON, sortPackage, updatePackage } from "pkg-types"; import pick from "lodash/pick"; import omit from "lodash/omit"; import cloneDeep from "lodash/cloneDeep"; @@ -933,6 +932,10 @@ export async function resolveEntryFiles({ ); } + // TODO(v8): Remove - only required for Node 20.18 and below + let { readPackageJSON, sortPackage, updatePackage } = await import( + "pkg-types" + ); let packageJsonDirectory = Path.dirname(packageJsonPath); let pkgJson = await readPackageJSON(packageJsonDirectory); let deps = pkgJson.dependencies ?? {}; diff --git a/packages/react-router-dev/package.json b/packages/react-router-dev/package.json index 89ea0e5ff8..257e5564a9 100644 --- a/packages/react-router-dev/package.json +++ b/packages/react-router-dev/package.json @@ -1,6 +1,6 @@ { "name": "@react-router/dev", - "version": "7.10.0", + "version": "7.10.1", "description": "Dev tools and CLI for React Router", "homepage": "https://reactrouter.com", "bugs": { @@ -90,7 +90,7 @@ "react-refresh": "^0.14.0", "semver": "^7.3.7", "tinyglobby": "^0.2.14", - "valibot": "^1.1.0", + "valibot": "^1.2.0", "vite-node": "^3.2.2" }, "devDependencies": { diff --git a/packages/react-router-dom/CHANGELOG.md b/packages/react-router-dom/CHANGELOG.md index 156553ae65..96e5671f9c 100644 --- a/packages/react-router-dom/CHANGELOG.md +++ b/packages/react-router-dom/CHANGELOG.md @@ -1,5 +1,12 @@ # react-router-dom +## 7.10.1 + +### Patch Changes + +- Updated dependencies: + - `react-router@7.10.1` + ## 7.10.0 ### Patch Changes diff --git a/packages/react-router-dom/package.json b/packages/react-router-dom/package.json index 0c460545e4..727dfb361c 100644 --- a/packages/react-router-dom/package.json +++ b/packages/react-router-dom/package.json @@ -1,6 +1,6 @@ { "name": "react-router-dom", - "version": "7.10.0", + "version": "7.10.1", "description": "Declarative routing for React web applications", "keywords": [ "react", diff --git a/packages/react-router-express/CHANGELOG.md b/packages/react-router-express/CHANGELOG.md index 7de371d64c..0902d58375 100644 --- a/packages/react-router-express/CHANGELOG.md +++ b/packages/react-router-express/CHANGELOG.md @@ -1,5 +1,13 @@ # `@react-router/express` +## 7.10.1 + +### Patch Changes + +- Updated dependencies: + - `react-router@7.10.1` + - `@react-router/node@7.10.1` + ## 7.10.0 ### Patch Changes diff --git a/packages/react-router-express/package.json b/packages/react-router-express/package.json index ed75dbe6e7..3ad6f94aaf 100644 --- a/packages/react-router-express/package.json +++ b/packages/react-router-express/package.json @@ -1,6 +1,6 @@ { "name": "@react-router/express", - "version": "7.10.0", + "version": "7.10.1", "description": "Express server request handler for React Router", "bugs": { "url": "https://github.com/remix-run/react-router/issues" diff --git a/packages/react-router-fs-routes/CHANGELOG.md b/packages/react-router-fs-routes/CHANGELOG.md index 5a11b3b4ce..319705480e 100644 --- a/packages/react-router-fs-routes/CHANGELOG.md +++ b/packages/react-router-fs-routes/CHANGELOG.md @@ -1,5 +1,12 @@ # `@react-router/fs-routes` +## 7.10.1 + +### Patch Changes + +- Updated dependencies: + - `@react-router/dev@7.10.1` + ## 7.10.0 ### Patch Changes diff --git a/packages/react-router-fs-routes/package.json b/packages/react-router-fs-routes/package.json index ede8aa593d..479a5fba0e 100644 --- a/packages/react-router-fs-routes/package.json +++ b/packages/react-router-fs-routes/package.json @@ -1,6 +1,6 @@ { "name": "@react-router/fs-routes", - "version": "7.10.0", + "version": "7.10.1", "description": "File system routing conventions for React Router, for use within routes.ts", "bugs": { "url": "https://github.com/remix-run/react-router/issues" diff --git a/packages/react-router-node/CHANGELOG.md b/packages/react-router-node/CHANGELOG.md index a36b0812a4..ff7d06d6dc 100644 --- a/packages/react-router-node/CHANGELOG.md +++ b/packages/react-router-node/CHANGELOG.md @@ -1,5 +1,12 @@ # `@react-router/node` +## 7.10.1 + +### Patch Changes + +- Updated dependencies: + - `react-router@7.10.1` + ## 7.10.0 ### Patch Changes diff --git a/packages/react-router-node/package.json b/packages/react-router-node/package.json index 677c6e4fe3..8a9c08565e 100644 --- a/packages/react-router-node/package.json +++ b/packages/react-router-node/package.json @@ -1,6 +1,6 @@ { "name": "@react-router/node", - "version": "7.10.0", + "version": "7.10.1", "description": "Node.js platform abstractions for React Router", "bugs": { "url": "https://github.com/remix-run/react-router/issues" diff --git a/packages/react-router-remix-routes-option-adapter/CHANGELOG.md b/packages/react-router-remix-routes-option-adapter/CHANGELOG.md index 141c35dd7f..951495cd51 100644 --- a/packages/react-router-remix-routes-option-adapter/CHANGELOG.md +++ b/packages/react-router-remix-routes-option-adapter/CHANGELOG.md @@ -1,5 +1,12 @@ # `@react-router/remix-config-routes-adapter` +## 7.10.1 + +### Patch Changes + +- Updated dependencies: + - `@react-router/dev@7.10.1` + ## 7.10.0 ### Patch Changes diff --git a/packages/react-router-remix-routes-option-adapter/package.json b/packages/react-router-remix-routes-option-adapter/package.json index da90307840..81bcc81091 100644 --- a/packages/react-router-remix-routes-option-adapter/package.json +++ b/packages/react-router-remix-routes-option-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@react-router/remix-routes-option-adapter", - "version": "7.10.0", + "version": "7.10.1", "description": "Adapter for Remix's \"routes\" config option, for use within routes.ts", "bugs": { "url": "https://github.com/remix-run/react-router/issues" diff --git a/packages/react-router-serve/CHANGELOG.md b/packages/react-router-serve/CHANGELOG.md index d615046e77..7b3f260d23 100644 --- a/packages/react-router-serve/CHANGELOG.md +++ b/packages/react-router-serve/CHANGELOG.md @@ -1,5 +1,14 @@ # `@react-router/serve` +## 7.10.1 + +### Patch Changes + +- Updated dependencies: + - `react-router@7.10.1` + - `@react-router/node@7.10.1` + - `@react-router/express@7.10.1` + ## 7.10.0 ### Patch Changes diff --git a/packages/react-router-serve/package.json b/packages/react-router-serve/package.json index 859abb7111..2e1cc65520 100644 --- a/packages/react-router-serve/package.json +++ b/packages/react-router-serve/package.json @@ -1,6 +1,6 @@ { "name": "@react-router/serve", - "version": "7.10.0", + "version": "7.10.1", "description": "Production application server for React Router", "bugs": { "url": "https://github.com/remix-run/react-router/issues" diff --git a/packages/react-router/CHANGELOG.md b/packages/react-router/CHANGELOG.md index dfe7f01353..39d50f8991 100644 --- a/packages/react-router/CHANGELOG.md +++ b/packages/react-router/CHANGELOG.md @@ -1,5 +1,11 @@ # `react-router` +## 7.10.1 + +### Patch Changes + +- Update the `useOptimistic` stub we provide for React 18 users to use a stable setter function to avoid potential `useEffect` loops - specifically when using `` ([#14628](https://github.com/remix-run/react-router/pull/14628)) + ## 7.10.0 ### Minor Changes diff --git a/packages/react-router/lib/components.tsx b/packages/react-router/lib/components.tsx index 8ed10893e8..64e6376751 100644 --- a/packages/react-router/lib/components.tsx +++ b/packages/react-router/lib/components.tsx @@ -77,8 +77,8 @@ import { warnOnce } from "./server-runtime/warnings"; import type { unstable_ClientInstrumentation } from "./router/instrumentation"; /** - * Webpack can fail to compile on against react versions without this export - * complains that `startTransition` doesn't exist in `React`. + * Webpack can fail to compile against react versions without this export - + * it complains that `useOptimistic` doesn't exist in `React`. * * Using the string constant directly at runtime fixes the webpack build issue * but can result in terser stripping the actual call at minification time. @@ -90,6 +90,7 @@ import type { unstable_ClientInstrumentation } from "./router/instrumentation"; const USE_OPTIMISTIC = "useOptimistic"; // @ts-expect-error Needs React 19 types but we develop against 18 const useOptimisticImpl = React[USE_OPTIMISTIC]; +const stableUseOptimisticSetter = () => undefined; function useOptimisticSafe( val: T, @@ -98,7 +99,7 @@ function useOptimisticSafe( // eslint-disable-next-line react-hooks/rules-of-hooks return useOptimisticImpl(val); } else { - return [val, () => undefined]; + return [val, stableUseOptimisticSetter]; } } diff --git a/packages/react-router/lib/dom/lib.tsx b/packages/react-router/lib/dom/lib.tsx index 6d192efaf7..d740bf6c06 100644 --- a/packages/react-router/lib/dom/lib.tsx +++ b/packages/react-router/lib/dom/lib.tsx @@ -1038,16 +1038,16 @@ HistoryRouter.displayName = "unstable_HistoryRouter"; export interface LinkProps extends Omit, "href"> { /** - * Defines the link discovery behavior + * Defines the link [lazy route discovery](../../explanation/lazy-route-discovery) behavior. + * + * - **render** — default, discover the route when the link renders + * - **none** — don't eagerly discover, only discover if the link is clicked * * ```tsx * // default ("render") * * * ``` - * - * - **render** — default, discover the route when the link renders - * - **none** — don't eagerly discover, only discover if the link is clicked */ discover?: DiscoverBehavior; @@ -1717,16 +1717,16 @@ export interface FetcherFormProps extends SharedFormProps {} */ export interface FormProps extends SharedFormProps { /** - * Defines the link discovery behavior. See {@link DiscoverBehavior}. + * Defines the form [lazy route discovery](../../explanation/lazy-route-discovery) behavior. + * + * - **render** — default, discover the route when the form renders + * - **none** — don't eagerly discover, only discover if the form is submitted * * ```tsx - * // default ("render") - * - * + * // default ("render") + * + * * ``` - * - * - **render** — default, discover the route when the link renders - * - **none** — don't eagerly discover, only discover if the link is clicked */ discover?: DiscoverBehavior; diff --git a/packages/react-router/lib/dom/ssr/components.tsx b/packages/react-router/lib/dom/ssr/components.tsx index 318fa0bf51..57edd93007 100644 --- a/packages/react-router/lib/dom/ssr/components.tsx +++ b/packages/react-router/lib/dom/ssr/components.tsx @@ -76,7 +76,8 @@ export function useFrameworkContext(): FrameworkContextObject { // Public API /** - * Defines the discovery behavior of the link: + * Defines the [lazy route discovery](../../explanation/lazy-route-discovery) + * behavior of the link/form: * * - "render" - default, discover the route when the link renders * - "none" - don't eagerly discover, only discover if the link is clicked diff --git a/packages/react-router/package.json b/packages/react-router/package.json index 29b8e5cc80..944f04dffa 100644 --- a/packages/react-router/package.json +++ b/packages/react-router/package.json @@ -1,6 +1,6 @@ { "name": "react-router", - "version": "7.10.0", + "version": "7.10.1", "description": "Declarative routing for React", "keywords": [ "react", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dd0281e157..af765b3984 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1120,8 +1120,8 @@ importers: specifier: ^0.2.14 version: 0.2.14 valibot: - specifier: ^1.1.0 - version: 1.1.0(typescript@5.4.5) + specifier: ^1.2.0 + version: 1.2.0(typescript@5.4.5) vite-node: specifier: ^3.2.2 version: 3.2.4(@types/node@20.11.30)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.3)(yaml@2.8.0) @@ -9507,8 +9507,8 @@ packages: typescript: optional: true - valibot@1.1.0: - resolution: {integrity: sha512-Nk8lX30Qhu+9txPYTwM0cFlWLdPFsFr6LblzqIySfbZph9+BFsAHsNvHOymEviUepeIW6KFHzpX8TKhbptBXXw==} + valibot@1.2.0: + resolution: {integrity: sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==} peerDependencies: typescript: '>=5' peerDependenciesMeta: @@ -19198,7 +19198,7 @@ snapshots: optionalDependencies: typescript: 5.4.5 - valibot@1.1.0(typescript@5.4.5): + valibot@1.2.0(typescript@5.4.5): optionalDependencies: typescript: 5.4.5