Skip to content

Fix unnecessary DOM mutations in updateInput for unchanged inputs (#36229)#36240

Open
aryashashank wants to merge 1 commit intofacebook:mainfrom
aryashashank:main
Open

Fix unnecessary DOM mutations in updateInput for unchanged inputs (#36229)#36240
aryashashank wants to merge 1 commit intofacebook:mainfrom
aryashashank:main

Conversation

@aryashashank
Copy link
Copy Markdown

Summary

Fixes #36229

React 19 introduced a performance regression in updateInput() (ReactDOMInput.js). On every commit, the function unconditionally performs three DOM mutations for every <input> element — even when none of the input-specific props (type, name, value, checked) have changed:

  1. node.name = '' — disconnects the input from its radio group
  2. node.type = type — rewrites the type property
  3. node.name = name — restores the name property

On pages with many <input> elements (e.g. 500+), this causes hundreds of unnecessary DOM writes per render, making updates significantly slower than React 18.

This PR adds change detection by comparing new values against the current DOM state before writing. The node.name = '' disconnection trick — which exists to ensure atomicity when changing type or name alongside checked for radio buttons — is now only performed when type or name is actually changing. All existing semantics, including radio button group behavior, are preserved.

How did you test this change?

Added two new tests to ReactDOMInput-test.js:

  1. "should not perform unnecessary DOM mutations for unchanged inputs" — Renders two inputs under a shared parent, installs an Object.defineProperty setter trap on the unchanged input's name property, then updates only the first input's value. The test verifies that the second input's name is never written to.

  2. "should not write type or name when they have not changed" — Renders an input, installs a setter trap on type that counts writes, then re-renders with identical props. The test verifies zero writes to type.

Ran the full test suites:

$ node scripts/jest/jest-cli.js packages/react-dom/src/tests/ReactDOMInput-test.js
Test Suites: 1 passed, 1 total
Tests: 126 passed, 126 total

$ node scripts/jest/jest-cli.js packages/react-dom/src/tests/ReactDOMServerIntegrationInput-test.js
Test Suites: 1 passed, 1 total
Tests: 35 passed, 35 total

ESLint and Prettier also pass on the changed files.

@meta-cla
Copy link
Copy Markdown

meta-cla bot commented Apr 9, 2026

Hi @aryashashank!

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 cla@meta.com. Thanks!

@aryashashank aryashashank marked this pull request as draft April 9, 2026 13:53
@meta-cla
Copy link
Copy Markdown

meta-cla bot commented Apr 9, 2026

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks!

@meta-cla meta-cla bot added the CLA Signed label Apr 9, 2026
@aryashashank aryashashank marked this pull request as ready for review April 9, 2026 13:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: React 19 significant performance regression with many <input> elements

1 participant