Skip to content

[DOM] Snapshot Fragment event listener options at registration - #37599

Open
Liuzikaii wants to merge 1 commit into
react:mainfrom
Liuzikaii:fix/fragment-listener-options
Open

Liuzikaii wants to merge 1 commit into
react:mainfrom
Liuzikaii:fix/fragment-listener-options

Conversation

@Liuzikaii

Copy link
Copy Markdown

Summary

Fragment refs keep the caller-owned listener options object and read it again later. Changing that object after registration can leave an event listener active after removeEventListener, once delivery or signal abort.

Fixes #37598

Root cause

StoredEventListener.optionsOrUseCapture aliases the caller object. indexOfEventListener and cleanup derive capture from the mutated object, although existing native listeners were attached using the original capture value.

Changes

Copy the supported option fields at registration time. Retain the snapshot for matching, once/abort cleanup and later children. Add regression tests for explicit removal, once and AbortSignal cleanup after capture mutation.

Before / after

Before: The listener remains active. A once listener may also fire again on another child, and abort cleanup can remove the registration record while leaving the original native listener attached.

After: Registration should keep the capture/options values read at addEventListener time, as the native API does. Removing the original non-capture listener should stop its callbacks.

How did you test this change?

Before: removal/later-child and once regressions each produce 2 calls instead of 0 and 1 respectively. After: both development and production Fragment suites pass 101/101 tests, including the new abort regression. ESLint, Prettier and Flow (dom-node-webpack configuration, which includes DOM bindings) pass.

yarn test ReactDOMFragmentRefs --runInBand --no-watchman
yarn test ReactDOMFragmentRefs --prod --runInBand --no-watchman
yarn flow dom-node-webpack

Validation ran on Windows. Dependencies were installed with frozen yarn.lock using the available Node 24.19.0 runtime; targeted test runs used the repository Jest CLI. Flow was invoked via node node_modules/flow-bin/cli.js status with the generated renderer configuration (the equivalent Windows CLI path). ESLint and Prettier were run directly on changed files. The entire repository test/build matrix was not run.

Compatibility and risks

Boolean and omitted options retain their existing behavior. Snapshotting reads the supported dictionary fields once and preserves optional passive defaults. No public API is added.

Related work

Searched all Issue/PR states for Fragment capture/options/mutated/snapshot and examined recent Fragment commits. #36047 and #37251 normalize equivalent option forms; #37457 handles aborted registration cleanup. They do not snapshot caller-owned options, and the new regressions fail on main after those fixes. No equivalent issue or PR was found.

@meta-cla

meta-cla Bot commented Sep 11, 2026

Copy link
Copy Markdown

Hi @Liuzikaii!

Thank you for your pull request and welcome to our community.

Action Required

In order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you.

Process

In order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA.

Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with CLA signed. The tagging process may take up to 1 hour after signing. Please give it that time before contacting us about it.

If you have received this in error or have any questions, please contact us at [email protected]. Thanks!

@github-actions

Copy link
Copy Markdown

A size report will appear here when the build finishes.

Generated by sizebot against 262b861

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Mutating Fragment listener options breaks removal, once and abort cleanup

1 participant