Repository navigation
Apply setNativeProps props to a cloned node only when they changed - #59624
Open
hryhoriiK97 wants to merge 1 commit into
Open
hryhoriiK97 wants to merge 1 commit into
hryhoriiK97 wants to merge 1 commit into
Conversation
Once a component's props were set with setNativeProps, every clone of its shadow nodes with unchanged props parsed nativeProps_DEPRECATED into new props again, including the clones Yoga makes of every child of a node it lays out. New props mark a Text's Yoga node dirty, so with JS-driven Animated (which uses setNativeProps on Fabric) every sibling Text was measured again in every frame. The family now counts changes to nativeProps_DEPRECATED, and each node records the count its props include. A clone applies nativeProps_DEPRECATED only when the node it clones is behind. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary:
Once a component's props are set with
setNativeProps,ShadowNode::cloneappliesfamily.nativeProps_DEPRECATEDagain every time one of its shadow nodes is cloned with unchanged props: it parses them into new props withcloneProps. That includes the clones Yoga makes of every child of a node it lays out (YogaLayoutableShadowNode::adoptYogaChild), so each commit that touches a parent re-parses the native props of all its children that ever hadsetNativeProps, andnativeProps_DEPRECATEDstays set for the life of the component.On Fabric, JS-driven
Animated(useNativeDriver: false) updates props withsetNativePropson every frame (shouldUseSetNativePropsInFabric, on by default). With several animated components under one parent, every frame re-parses the props of all of them, not just the one being updated. For aText, new props also mark its Yoga node dirty (ParagraphShadowNode::shouldNewRevisionDirtyMeasurement), so all of them are measured again. In a list of 30 JS-animated texts, on Android that was ~16,000measurePreparedLayoutcalls per second (~40 per frame), and on iOS props parsing was 27–28% of the JS thread.With this change,
ShadowNodeFamilycounts changes tonativeProps_DEPRECATED(setNativeProps_DEPRECATED, andUIManager::cloneNodewhen a React render updates them), and each shadow node records the count its props include. A clone with unchanged props keeps the source node's count;ShadowNode::cloneappliesnativeProps_DEPRECATEDonly when the node it clones is behind, exactly as before in every other case. So native props are still applied aftersetNativePropsand after a React render replaces a node's props; they are only no longer parsed again into props that already include them.Changelog:
[GENERAL] [CHANGED] - Fabric no longer parses the props set by setNativeProps again on every clone of a component's shadow nodes
Test Plan:
FabricUIManagerTestcases: aftersetNativeProps_DEPRECATED, a clone of a node whose props include them keeps the same props object, and a latersetNativeProps_DEPRECATEDis applied to the next clone; after a React render (cloneNode) replaces a node's props, the next clone applies the native props again. These C++ tests run internally; locally I compiled the test file against the real headers with a stub gtest (clang++ -fsyntax-only), as OSS CI doesn't run ReactCommon gtests.yarn fantomwith thesetNativePropsreconciliation tests (Mounting-itest.js,ReactNativeElement-itest.js) and the Animated suites that drive JS animations throughsetNativeProps(AnimatedComponents,AnimatedComposition,AnimatedValue,TimingAnimation): 6 suites, 285 tests pass.node scripts/clang-format.js --checkreports no changes for the touched files.ShadowNodeFamilyfield is excluded by_DEPRECATEDand the newShadowNodefield is private.Animated.Textrows with JS-driven loops (even rows animatecolor, odd rowsfontSize), RNTester release builds:mainat f7de203 with local benchmark screens and call counters), installed alternately, 20 s per run, three rounds. "Before" is a build with this check behind a runtime switch, turned off, soclonere-appliesnativeProps_DEPRECATEDevery time as onmain; "this PR" is this change as is:measurePreparedLayoutJNI calls per secondTextdraws per second (animation throughput)TextdrawA control screen without
setNativeProps(200 single-style numbers changing every 100 ms) is unchanged: JS time per text layout 0.45 → 0.44 ms, main thread 2.30 → 2.33 s.clonePropsand its callees) fell from 27–28% of the JS thread (1,608 / 2,708 ms) to 4.4–4.5% (158 / 208 ms). Total JS and main-thread times varied too much between runs on this phone to compare.🤖 Generated with Claude Code