From 67e24bc5279204108b749fe48b4d395ef9e49e67 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Wed, 1 Oct 2025 15:17:08 -0400 Subject: [PATCH 1/6] Improve lint error messages for useEffectEvent (#34669) Called Before: > `logEvent` is a function created with React Hook "useEffectEvent", and can only be called from the same component. Called After: > `logEvent` is a function created with React Hook "useEffectEvent", and can only be called from Effects and Effect Events in the same component. Referenced Before: > `logEvent` is a function created with React Hook "useEffectEvent", and can only be called from the same component. They cannot be assigned to variables or passed down. Referenced After: > `logEvent` is a function created with React Hook "useEffectEvent", and can only be called from Effects and Effect Events in the same component. It cannot be assigned to a variable or passed down. --- .../__tests__/ESLintRulesOfHooks-test.js | 22 ++++++++++++++++--- .../src/rules/RulesOfHooks.ts | 22 ++++++++++++------- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js b/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js index bfde0e69e16a6..3e89624c6d3f1 100644 --- a/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js +++ b/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js @@ -1637,17 +1637,32 @@ const allTests = { const onClick = useEffectEvent(() => { showNotification(theme); }); + // error message 1 const onClick2 = () => { onClick() }; + // error message 2 const onClick3 = useCallback(() => onClick(), []); + // error message 3 + const onClick4 = onClick; return <> + {/** error message 4 */} + ; } `, + // Explicitly test error messages here for various cases errors: [ - useEffectEventError('onClick', true), - useEffectEventError('onClick', true), + `\`onClick\` is a function created with React Hook "useEffectEvent", and can only be called from ` + + 'Effects and Effect Events in the same component.', + `\`onClick\` is a function created with React Hook "useEffectEvent", and can only be called from ` + + 'Effects and Effect Events in the same component.', + `\`onClick\` is a function created with React Hook "useEffectEvent", and can only be called from ` + + `Effects and Effect Events in the same component. ` + + `It cannot be assigned to a variable or passed down.`, + `\`onClick\` is a function created with React Hook "useEffectEvent", and can only be called from ` + + `Effects and Effect Events in the same component. ` + + `It cannot be assigned to a variable or passed down.`, ], }, ], @@ -1714,7 +1729,8 @@ function useEffectEventError(fn, called) { return { message: `\`${fn}\` is a function created with React Hook "useEffectEvent", and can only be called from ` + - `the same component.${called ? '' : ' They cannot be assigned to variables or passed down.'}`, + 'Effects and Effect Events in the same component.' + + (called ? '' : ' It cannot be assigned to a variable or passed down.'), }; } diff --git a/packages/eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts b/packages/eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts index cb89bbfea9c49..ba398d850dedb 100644 --- a/packages/eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts +++ b/packages/eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts @@ -166,10 +166,19 @@ function isEffectIdentifier(node: Node, additionalHooks?: RegExp): boolean { return false; } + function isUseEffectEventIdentifier(node: Node): boolean { return node.type === 'Identifier' && node.name === 'useEffectEvent'; } +function useEffectEventError(fn: string, called: boolean): string { + return ( + `\`${fn}\` is a function created with React Hook "useEffectEvent", and can only be called from ` + + 'Effects and Effect Events in the same component.' + + (called ? '' : ' It cannot be assigned to a variable or passed down.') + ); +} + function isUseIdentifier(node: Node): boolean { return isReactFunction(node, 'use'); } @@ -769,14 +778,11 @@ const rule = { // This identifier resolves to a useEffectEvent function, but isn't being referenced in an // effect or another event function. It isn't being called either. if (lastEffect == null && useEffectEventFunctions.has(node)) { - const message = - `\`${getSourceCode().getText( - node, - )}\` is a function created with React Hook "useEffectEvent", and can only be called from ` + - 'the same component.' + - (node.parent.type === 'CallExpression' - ? '' - : ' They cannot be assigned to variables or passed down.'); + const message = useEffectEventError( + getSourceCode().getText(node), + node.parent.type === 'CallExpression', + ); + context.report({ node, message, From aef8b1b562ed7db87ae9552e44168a54af84aaf8 Mon Sep 17 00:00:00 2001 From: "Sebastian \"Sebbie\" Silbermann" Date: Wed, 1 Oct 2025 22:11:02 +0200 Subject: [PATCH 2/6] 19.2 changelog (#34655) Co-authored-by: Jack Pope Co-authored-by: Rick Hanlon --- CHANGELOG.md | 73 +++++++++++++++++++ .../eslint-plugin-react-hooks/CHANGELOG.md | 15 ++++ 2 files changed, 88 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1836850ff3ea2..21704e3e29f64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,76 @@ +## 19.2.0 (October 1st, 2025) + +Below is a list of all new features, APIs, and bug fixes. + +Read the [React 19.2 release post](https://react.dev/blog/2025/10/01/react-19-2) for more information. + +### New React Features + +- [``](https://react.dev/reference/react/Activity): A new API to hide and restore the UI and internal state of its children. +- [`useEffectEvent`](https://react.dev/reference/react/useEffectEvent) is a React Hook that lets you extract non-reactive logic into an [Effect Event](https://react.dev/learn/separating-events-from-effects#declaring-an-effect-event). +- [`cacheSignal`](https://react.dev/reference/react/cacheSignal) (for RSCs) lets your know when the `cache()` lifetime is over. +- [React Performance tracks](https://react.dev/reference/developer-tooling/react-performance-tracks) appear on the Performance panel’s timeline in your browser developer tools + +### New React DOM Features + +- Added resume APIs for partial pre-rendering with Web Streams: + - [`resume`](https://react.dev/reference/react-dom/server/resume): to resume a prerender to a stream. + - [`resumeAndPrerender`](https://react.dev/reference/react-dom/static/resumeAndPrerender): to resume a prerender to HTML. +- Added resume APIs for partial pre-rendering with Node Streams: + - [`resumeToPipeableStream`](https://react.dev/reference/react-dom/server/resumeToPipeableStream): to resume a prerender to a stream. + - [`resumeAndPrerenderToNodeStream`](https://react.dev/reference/react-dom/static/resumeAndPrerenderToNodeStream): to resume a prerender to HTML. +- Updated [`prerender`](https://react.dev/reference/react-dom/static/prerender) APIs to return a `postponed` state that can be passed to the `resume` APIs. + +### Notable changes + +- React DOM now batches suspense boundary reveals, matching the behavior of client side rendering. This change is especially noticeable when animating the reveal of Suspense boundaries e.g. with the upcoming `` Component. React will batch as much reveals as possible before the first paint while trying to hit popular first-contentful paint metrics. +- Add Node Web Streams (`prerender`, `renderToReadableStream`) to server-side-rendering APIs for Node.js +- Use underscore instead of `:` IDs generated by useId + +### All Changes + +#### React + +- `` was developed over many years, starting before `ClassComponent.setState` (@acdlite @sebmarkbage and many others) +- Stringify context as "SomeContext" instead of "SomeContext.Provider" (@kassens [#33507](https://github.com/facebook/react/pull/33507)) +- Include stack of cause of React instrumentation errors with `%o` placeholder (@eps1lon [#34198](https://github.com/facebook/react/pull/34198)) +- Fix infinite `useDeferredValue` loop in popstate event (@acdlite [#32821](https://github.com/facebook/react/pull/32821)) +- Fix a bug when an initial value was passed to `useDeferredValue` (@acdlite [#34376](https://github.com/facebook/react/pull/34376)) +- Fix a crash when submitting forms with Client Actions (@sebmarkbage [#33055](https://github.com/facebook/react/pull/33055)) +- Hide/unhide the content of dehydrated suspense boundaries if they resuspend (@sebmarkbage [#32900](https://github.com/facebook/react/pull/32900)) +- Avoid stack overflow on wide trees during Hot Reload (@sophiebits [#34145](https://github.com/facebook/react/pull/34145)) +- Improve Owner and Component stacks in various places (@sebmarkbage, @eps1lon: [#33629](https://github.com/facebook/react/pull/33629), [#33724](https://github.com/facebook/react/pull/33724), [#32735](https://github.com/facebook/react/pull/32735), [#33723](https://github.com/facebook/react/pull/33723)) +- Add `cacheSignal` (@sebmarkbage [#33557](https://github.com/facebook/react/pull/33557)) + +#### React DOM + +- Block on Suspensey Fonts during reveal of server-side-rendered content (@sebmarkbage [#33342](https://github.com/facebook/react/pull/33342)) +- Use underscore instead of `:` for IDs generated by `useId` (@sebmarkbage, @eps1lon: [#32001](https://github.com/facebook/react/pull/32001), [https://github.com/facebook/react/pull/33342](https://github.com/facebook/react/pull/33342)[#33099](https://github.com/facebook/react/pull/33099), [#33422](https://github.com/facebook/react/pull/33422)) +- Stop warning when ARIA 1.3 attributes are used (@Abdul-Omira [#34264](https://github.com/facebook/react/pull/34264)) +- Allow `nonce` to be used on hoistable styles (@Andarist [#32461](https://github.com/facebook/react/pull/32461)) +- Warn for using a React owned node as a Container if it also has text content (@sebmarkbage [#32774](https://github.com/facebook/react/pull/32774)) +- s/HTML/text for for error messages if text hydration mismatches (@rickhanlonii [#32763](https://github.com/facebook/react/pull/32763)) +- Fix a bug with `React.use` inside `React.lazy`\-ed Component (@hi-ogawa [#33941](https://github.com/facebook/react/pull/33941)) +- Enable the `progressiveChunkSize` option for server-side-rendering APIs (@sebmarkbage [#33027](https://github.com/facebook/react/pull/33027)) +- Fix a bug with deeply nested Suspense inside Suspense fallback when server-side-rendering (@gnoff [#33467](https://github.com/facebook/react/pull/33467)) +- Avoid hanging when suspending after aborting while rendering (@gnoff [#34192](https://github.com/facebook/react/pull/34192)) +- Add Node Web Streams to server-side-rendering APIs for Node.js (@sebmarkbage [#33475](https://github.com/facebook/react/pull/33475)) + +#### React Server Components + +- Preload `` and `` using hints before they're rendered (@sebmarkbage [#34604](https://github.com/facebook/react/pull/34604)) +- Log error if production elements are rendered during development (@eps1lon [#34189](https://github.com/facebook/react/pull/34189)) +- Fix a bug when returning a Temporary reference (e.g. a Client Reference) from Server Functions (@sebmarkbage [#34084](https://github.com/facebook/react/pull/34084), @denk0403 [#33761](https://github.com/facebook/react/pull/33761)) +- Pass line/column to `filterStackFrame` (@eps1lon [#33707](https://github.com/facebook/react/pull/33707)) +- Support Async Modules in Turbopack Server References (@lubieowoce [#34531](https://github.com/facebook/react/pull/34531)) +- Add support for .mjs file extension in Webpack (@jennyscript [#33028](https://github.com/facebook/react/pull/33028)) +- Fix a wrong missing key warning (@unstubbable [#34350](https://github.com/facebook/react/pull/34350)) +- Make console log resolve in predictable order (@sebmarkbage [#33665](https://github.com/facebook/react/pull/33665)) + +#### React Reconciler + +- [createContainer](https://github.com/facebook/react/blob/v19.2.0/packages/react-reconciler/src/ReactFiberReconciler.js#L255-L261) and [createHydrationContainer](https://github.com/facebook/react/blob/v19.2.0/packages/react-reconciler/src/ReactFiberReconciler.js#L305-L312) had their parameter order adjusted after `on*` handlers to account for upcoming experimental APIs + ## 19.1.1 (July 28, 2025) ### React diff --git a/packages/eslint-plugin-react-hooks/CHANGELOG.md b/packages/eslint-plugin-react-hooks/CHANGELOG.md index b1e552e434f63..b4243fbfddb2e 100644 --- a/packages/eslint-plugin-react-hooks/CHANGELOG.md +++ b/packages/eslint-plugin-react-hooks/CHANGELOG.md @@ -1,3 +1,18 @@ +## 6.1.0 + +**Note:** Version 6.0.0 was mistakenly released and immediately deprecated and untagged on npm. This is the first official 6.x major release and includes breaking changes. + +- **Breaking:** Require Node.js 18 or newer. ([@michaelfaith](https://github.com/michaelfaith) in [#32458](https://github.com/facebook/react/pull/32458)) +- **Breaking:** Flat config is now the default `recommended` preset. Legacy config moved to `recommended-legacy`. ([@michaelfaith](https://github.com/michaelfaith) in [#32457](https://github.com/facebook/react/pull/32457)) +- **New Violations:** Disallow calling `use` within try/catch blocks. ([@poteto](https://github.com/poteto) in [#34040](https://github.com/facebook/react/pull/34040)) +- **New Violations:** Disallow calling `useEffectEvent` functions in arbitrary closures. ([@jbrown215](https://github.com/jbrown215) in [#33544](https://github.com/facebook/react/pull/33544)) +- Handle `React.useEffect` in addition to `useEffect` in rules-of-hooks. ([@Ayc0](https://github.com/Ayc0) in [#34076](https://github.com/facebook/react/pull/34076)) +- Added `react-hooks` settings config option that to accept `additionalEffectHooks` that are used across exhaustive-deps and rules-of-hooks rules. ([@jbrown215](https://github.com/jbrown215)) in [#34497](https://github.com/facebook/react/pull/34497) + +## 6.0.0 + +Accidentally released. See 6.1.0 for the actual changes. + ## 5.2.0 - Support flat config ([@michaelfaith](https://github.com/michaelfaith) in [#30774](https://github.com/facebook/react/pull/30774)) From 7f9d99749c95d69b23efaa328c4388d73a39bf50 Mon Sep 17 00:00:00 2001 From: Ricky Date: Wed, 1 Oct 2025 16:31:30 -0400 Subject: [PATCH 3/6] Land enableHiddenSubtreeInsertionEffectCleanup (#34372) Fixes a bug where insertion effects were not cleaned up if a hidden Activity is unmounted. --- packages/shared/ReactFeatureFlags.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index a37adfea434a3..89095e7318321 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -166,7 +166,7 @@ export const renameElementSymbol: boolean = true; /** * Enables a fix to run insertion effect cleanup on hidden subtrees. */ -export const enableHiddenSubtreeInsertionEffectCleanup: boolean = false; +export const enableHiddenSubtreeInsertionEffectCleanup: boolean = true; /** * Removes legacy style context defined using static `contextTypes` and consumed with static `childContextTypes`. From 861811347b8fa936b4a114fc022db9b8253b3d86 Mon Sep 17 00:00:00 2001 From: "Sebastian \"Sebbie\" Silbermann" Date: Wed, 1 Oct 2025 22:45:31 +0200 Subject: [PATCH 4/6] Bump scheduler version (#34671) The canaries have been published depending on 0.27-canary. Bumping scheduler just in case to be sure. --- packages/react-art/package.json | 2 +- packages/react-dom/package.json | 2 +- packages/react-native-renderer/package.json | 2 +- packages/react-reconciler/package.json | 2 +- packages/react-server-dom-fb/package.json | 2 +- packages/react-test-renderer/package.json | 2 +- packages/scheduler/package.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/react-art/package.json b/packages/react-art/package.json index aded0ddf9ba25..f1435bcaa34c7 100644 --- a/packages/react-art/package.json +++ b/packages/react-art/package.json @@ -24,7 +24,7 @@ "dependencies": { "art": "^0.10.1", "create-react-class": "^15.6.2", - "scheduler": "^0.26.0" + "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" diff --git a/packages/react-dom/package.json b/packages/react-dom/package.json index 63e1008fdbab0..39a3b3d6360bc 100644 --- a/packages/react-dom/package.json +++ b/packages/react-dom/package.json @@ -17,7 +17,7 @@ }, "homepage": "https://react.dev/", "dependencies": { - "scheduler": "^0.26.0" + "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" diff --git a/packages/react-native-renderer/package.json b/packages/react-native-renderer/package.json index 8bdb25162c405..9b3862eb2f5bb 100644 --- a/packages/react-native-renderer/package.json +++ b/packages/react-native-renderer/package.json @@ -8,7 +8,7 @@ "directory": "packages/react-native-renderer" }, "dependencies": { - "scheduler": "^0.26.0" + "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^18.0.0" diff --git a/packages/react-reconciler/package.json b/packages/react-reconciler/package.json index 2fd6e6ed14075..8864374f92ecd 100644 --- a/packages/react-reconciler/package.json +++ b/packages/react-reconciler/package.json @@ -29,6 +29,6 @@ "react": "^19.2.0" }, "dependencies": { - "scheduler": "^0.26.0" + "scheduler": "^0.27.0" } } diff --git a/packages/react-server-dom-fb/package.json b/packages/react-server-dom-fb/package.json index ae3308175bdc2..f2da79e750b1f 100644 --- a/packages/react-server-dom-fb/package.json +++ b/packages/react-server-dom-fb/package.json @@ -8,7 +8,7 @@ "directory": "packages/react-server-dom-fb" }, "dependencies": { - "scheduler": "^0.26.0" + "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^18.0.0", diff --git a/packages/react-test-renderer/package.json b/packages/react-test-renderer/package.json index 8df23b8f6efaf..f15badfeadc95 100644 --- a/packages/react-test-renderer/package.json +++ b/packages/react-test-renderer/package.json @@ -20,7 +20,7 @@ "homepage": "https://react.dev/", "dependencies": { "react-is": "^19.2.0", - "scheduler": "^0.26.0" + "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" diff --git a/packages/scheduler/package.json b/packages/scheduler/package.json index fbdf280b107c1..56ac6297a4b13 100644 --- a/packages/scheduler/package.json +++ b/packages/scheduler/package.json @@ -1,6 +1,6 @@ { "name": "scheduler", - "version": "0.26.0", + "version": "0.27.0", "description": "Cooperative scheduler for the browser environment.", "repository": { "type": "git", From ae74234eae6ebd62f19190731278e20bc1c37d51 Mon Sep 17 00:00:00 2001 From: lauren Date: Wed, 1 Oct 2025 17:05:42 -0400 Subject: [PATCH 5/6] [eprh] Allow compiler rules to be opted-in but not in the preset (#34672) Follow up to #34649. This adds the compiler rules back so they can be opted-in 6.1.0, but aren't included in the presets as that would be a breaking change. --- packages/eslint-plugin-react-hooks/src/index.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/eslint-plugin-react-hooks/src/index.ts b/packages/eslint-plugin-react-hooks/src/index.ts index 2235e8d5a6845..c01e22fb4bb8d 100644 --- a/packages/eslint-plugin-react-hooks/src/index.ts +++ b/packages/eslint-plugin-react-hooks/src/index.ts @@ -7,12 +7,16 @@ import type {Linter, Rule} from 'eslint'; import ExhaustiveDeps from './rules/ExhaustiveDeps'; +import {allRules} from './shared/ReactCompiler'; import RulesOfHooks from './rules/RulesOfHooks'; // All rules const rules = { 'exhaustive-deps': ExhaustiveDeps, 'rules-of-hooks': RulesOfHooks, + ...Object.fromEntries( + Object.entries(allRules).map(([name, config]) => [name, config.rule]), + ), } satisfies Record; // Config rules From 79ca5ae8557e903f225c9ae61fa4db981ac87dfa Mon Sep 17 00:00:00 2001 From: "Sebastian \"Sebbie\" Silbermann" Date: Thu, 2 Oct 2025 00:31:55 +0200 Subject: [PATCH 6/6] Bump next prerelease version numbers (#34674) --- ReactVersions.js | 20 +++++++++---------- packages/react-art/package.json | 6 +++--- packages/react-dom-bindings/package.json | 2 +- packages/react-dom/package.json | 6 +++--- packages/react-is/package.json | 2 +- packages/react-markup/package.json | 2 +- packages/react-native-renderer/package.json | 2 +- packages/react-reconciler/package.json | 6 +++--- packages/react-refresh/package.json | 2 +- packages/react-server-dom-esm/package.json | 2 +- packages/react-server-dom-fb/package.json | 2 +- packages/react-server-dom-parcel/package.json | 6 +++--- .../react-server-dom-turbopack/package.json | 6 +++--- .../react-server-dom-webpack/package.json | 6 +++--- packages/react-test-renderer/package.json | 8 ++++---- packages/react/package.json | 2 +- packages/scheduler/package.json | 2 +- packages/shared/ReactVersion.js | 2 +- packages/use-subscription/package.json | 2 +- packages/use-sync-external-store/package.json | 2 +- 20 files changed, 44 insertions(+), 44 deletions(-) diff --git a/ReactVersions.js b/ReactVersions.js index 6ee0dae837920..c657857cbbc82 100644 --- a/ReactVersions.js +++ b/ReactVersions.js @@ -7,18 +7,18 @@ // // The @latest channel uses the version as-is, e.g.: // -// 19.2.0 +// 19.3.0 // // The @canary channel appends additional information, with the scheme // -