Skip to content

Skip View prop transforms when no transformed props are passed - #59102

Open
shubh73 wants to merge 3 commits into
react:mainfrom
shubh73:view-props-fast-path
Open

shubh73 wants to merge 3 commits into
react:mainfrom
shubh73:view-props-fast-path

Conversation

@shubh73

@shubh73 shubh73 commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Summary:

View copies its props and runs about 15 checks on every render to map aria-*, id and tabIndex onto their native equivalents. Most Views set none of these, so this checks the 17 keys first and, if none is set, passes props straight to ViewNativeComponent. Views that set any of them take the existing path, unchanged.

The transforms stay in JS, where #56699 left them; this only skips them when there's nothing to transform. A new test fails if the keys needsPropTransforms checks drift from the ones transformProps reads.

Native props are unchanged. On device, I recorded every payload sent to createNode/cloneNodeWithNewProps, before and after, across 2,516 random mount/update steps: keys and values match in every step. In 3 updates, a removed key appears in a different position; native reads props by name, so this isn't observable.

Fantom (View-propTransforms-benchmark-itest.js, release tester, 100 Views, median of 5 runs)

Case Before After Change
Mount, plain 507 µs 455 µs -10.2%
Update, plain 527 µs 485 µs -7.9%
Mount, testID + pointerEvents 599 µs 512 µs -14.5%
Mount, aria-label 547 µs 560 µs +2.5%
Update, aria-label 553 µs 568 µs +2.6%
Mount, accessibilityState 595 µs 603 µs +1.4%

The existing View-vs-ViewNativeComponent benchmark goes from 527 µs to 468 µs (-11.2%).

Device (OPPO CPH2667, Dimensity 6300, RNTester release build, 500–600 Views, median of 3 × 100 runs)

Case Before After Change
Mount, plain 24.3 ms 23.2 ms -4.6%
Update, plain 19.2 ms 18.3 ms -5.0%
Mount, testID + pointerEvents + hitSlop 28.2 ms 26.2 ms -6.9%
Update, testID + pointerEvents + hitSlop 21.1 ms 19.3 ms -8.6%
Mount, list rows (6 nested Views) 30.8 ms 29.3 ms -4.8%
Update, list rows (6 nested Views) 11.3 ms 10.5 ms -6.4%
Mount, aria-label 25.5 ms 25.7 ms +0.9%
Update, aria-label 19.9 ms 20.1 ms +1.1%
Mount, accessibilityState + accessibilityValue 31.8 ms 32.1 ms +1.1%
Update, accessibilityState + accessibilityValue 24.3 ms 24.3 ms +0.3%

Device times are JS-thread time for the whole update, including commit and layout, so the relative change is smaller than in Fantom. That's 1.2–3.9 µs saved per View.

Changelog:

[GENERAL] [CHANGED] - Skip View prop transforms when no aria-*, id or tabIndex props are passed

Test Plan:

  • yarn test packages/react-native: 5241 passed, including the new View-propTransforms-test.
  • yarn fantom packages/react-native/Libraries/Components/View: 259 passed.
  • yarn flow-check, ESLint, Prettier: clean.
  • Differential Jest test against the previous View (not committed): ~25k prop combinations, comparing iOS and Android create and diff payloads. All match.
  • On device: the payload recording above (APK from main vs. this branch), plus uiautomator dumps of RNTester's Accessibility and View examples. The same 617 accessibility nodes before and after.

🤖 Generated with Claude Code

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 15, 2026
View copies its props and checks 17 keys on every render to map aria-*,
id and tabIndex onto their native equivalents. Most Views pass none of
them, so check first and pass props through unchanged in that case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shubh73
shubh73 force-pushed the view-props-fast-path branch from c30e425 to 4f7fee2 Compare October 15, 2026 10:25
shubh73 and others added 2 commits October 15, 2026 16:05
Parses View.js and checks that `needsPropTransforms` reads exactly the
keys `transformProps` destructures, so adding a transform without
updating the check fails instead of silently skipping it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shubh73
shubh73 marked this pull request as ready for review October 15, 2026 10:50
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Oct 15, 2026

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

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant