From 644b5a55d4ac18c1c79389ff0047f0299af8c7db Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Wed, 3 Jun 2026 06:07:43 -0700 Subject: [PATCH] Avoid redundant dynamic_pointer_cast in YogaLayoutableShadowNode clone (#57019) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: The clone constructor of `YogaLayoutableShadowNode` rebuilt the internal `yogaLayoutableChildren_` vector on every clone by walking every child with `dynamic_pointer_cast`. When the cloned node inherits its children list from the source (`!fragment.children`) the result is identical to the source's vector, so copy it directly instead — no RTTI required. Also `reserve()` the vector to its upper bound at the top of `updateYogaChildren()` so the rebuild on the new-children path no longer reallocates as it grows. Both changes are pure CPU-time optimizations on a hot path that shows up heavily in animation-driven tree clones; behaviour is unchanged. Changelog: [Internal] Reviewed By: christophpurrer, lenaic Differential Revision: D106287171 --- .../view/YogaLayoutableShadowNode.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp index 2fe7f96c02ab..8785963fd646 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp @@ -114,11 +114,19 @@ YogaLayoutableShadowNode::YogaLayoutableShadowNode( "Yoga node must inherit dirty flag."); #endif if (!getTraits().check(ShadowNodeTraits::Trait::LeafYogaNode)) { - for (auto& child : getChildren()) { - if (auto layoutableChild = - std::dynamic_pointer_cast( - child)) { - yogaLayoutableChildren_.push_back(std::move(layoutableChild)); + if (!fragment.children) { + // Children unchanged - copy the filtered list directly from the source + // node, avoiding expensive dynamic_pointer_cast on every child. + yogaLayoutableChildren_ = + static_cast(sourceShadowNode) + .yogaLayoutableChildren_; + } else { + for (auto& child : getChildren()) { + if (auto layoutableChild = + std::dynamic_pointer_cast( + child)) { + yogaLayoutableChildren_.push_back(std::move(layoutableChild)); + } } } } @@ -349,6 +357,7 @@ void YogaLayoutableShadowNode::updateYogaChildren() { yogaNode_.setChildren({}); yogaLayoutableChildren_.clear(); + yogaLayoutableChildren_.reserve(getChildren().size()); for (size_t i = 0; i < getChildren().size(); i++) { if (auto yogaLayoutableChild =