From 1a6e8bedfe774a6cb6d1b31c05aa30819ce9d0ca Mon Sep 17 00:00:00 2001 From: Ngoc Le Date: Sat, 22 Aug 2026 23:37:30 +0700 Subject: [PATCH 1/2] fix(Reanimated): preserve entering animation layout updates --- .../LayoutAnimationsProxy_Experimental.cpp | 7 +++++-- .../LayoutAnimationsProxy_Experimental.h | 2 +- .../LayoutAnimations/LayoutAnimationsProxy_Legacy.cpp | 11 ++++++----- .../LayoutAnimations/LayoutAnimationsProxy_Legacy.h | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.cpp b/packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.cpp index bc626808ace0..405b4ff85386 100644 --- a/packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.cpp +++ b/packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.cpp @@ -244,6 +244,9 @@ void LayoutAnimationsProxy_Experimental::updateLightTree( if (layoutAnimationsManager_->hasLayoutAnimation(tag, LAYOUT)) { layout_.push_back(node); } else { + if (layoutAnimations_.contains(tag)) { + updateOngoingAnimationTarget(tag, node->current); + } filteredMutations.push_back(mutation); } break; @@ -713,9 +716,9 @@ bool LayoutAnimationsProxy_Experimental::startAnimationsRecursively( return wantAnimateExit; } -void LayoutAnimationsProxy_Experimental::updateOngoingAnimationTarget(const int tag, const ShadowViewMutation &mutation) +void LayoutAnimationsProxy_Experimental::updateOngoingAnimationTarget(const int tag, const ShadowView &finalView) const { - layoutAnimations_[tag].finalView = mutation.newChildShadowView; + layoutAnimations_[tag].finalView = finalView; } void LayoutAnimationsProxy_Experimental::maybeCancelAnimation(const int tag) const { diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.h b/packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.h index 325521ebaddd..cff4cc71ab24 100644 --- a/packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.h +++ b/packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.h @@ -194,7 +194,7 @@ struct LayoutAnimationsProxy_Experimental : public LayoutAnimationsProxyCommon, void handleRemovals(ShadowViewMutationList &filteredMutations, std::vector> &roots) const; void addOngoingAnimations(SurfaceId surfaceId, ShadowViewMutationList &mutations) const; - void updateOngoingAnimationTarget(const int tag, const ShadowViewMutation &mutation) const; + void updateOngoingAnimationTarget(const int tag, const ShadowView &finalView) const; ShadowView cloneViewWithoutOpacity(const ShadowView &shadowView, const PropsParserContext &propsParserContext) const; ShadowView cloneViewWithOpacity(const ShadowView &shadowView, const PropsParserContext &propsParserContext) const; diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Legacy.cpp b/packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Legacy.cpp index 58dd371feddb..8ccb68a97425 100644 --- a/packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Legacy.cpp +++ b/packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Legacy.cpp @@ -459,6 +459,9 @@ void LayoutAnimationsProxy_Legacy::handleUpdatesAndEnterings( auto shouldAnimate = hasLayoutChanged(mutation); if (!layoutAnimationsManager_->hasLayoutAnimation(tag, LayoutAnimationType::LAYOUT) || (!shouldAnimate && !layoutAnimations_.contains(tag))) { + if (layoutAnimations_.contains(tag)) { + updateOngoingAnimationTarget(tag, mutation.newChildShadowView); + } // We should cancel any ongoing animation here to ensure that the // proper final state is reached for this view However, due to how // RNSScreens handle adding headers (a second commit is triggered to @@ -469,7 +472,7 @@ void LayoutAnimationsProxy_Legacy::handleUpdatesAndEnterings( filteredMutations.push_back(mutation); continue; } else if (!shouldAnimate) { - updateOngoingAnimationTarget(tag, mutation); + updateOngoingAnimationTarget(tag, mutation.newChildShadowView); continue; } @@ -943,10 +946,8 @@ void LayoutAnimationsProxy_Legacy::startLayoutAnimation(const int tag, const Sha }); } -void LayoutAnimationsProxy_Legacy::updateOngoingAnimationTarget(const int tag, const ShadowViewMutation &mutation) - const { - auto copy = mutation.newChildShadowView; - layoutAnimations_[tag].finalView = copy; +void LayoutAnimationsProxy_Legacy::updateOngoingAnimationTarget(const int tag, const ShadowView &finalView) const { + layoutAnimations_[tag].finalView = finalView; } void LayoutAnimationsProxy_Legacy::maybeCancelAnimation(const int tag) const { diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Legacy.h b/packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Legacy.h index 11609da9363a..06f3e1d660d0 100644 --- a/packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Legacy.h +++ b/packages/react-native-reanimated/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Legacy.h @@ -187,7 +187,7 @@ struct LayoutAnimationsProxy_Legacy : public LayoutAnimationsProxyCommon, SurfaceId surfaceId) const; void addOngoingAnimations(SurfaceId surfaceId, ShadowViewMutationList &mutations) const; void dropUpdatesForDeletedViews(ShadowViewMutationList &filteredMutations) const; - void updateOngoingAnimationTarget(const int tag, const ShadowViewMutation &mutation) const; + void updateOngoingAnimationTarget(const int tag, const ShadowView &finalView) const; std::shared_ptr cloneViewWithoutOpacity( facebook::react::ShadowViewMutation &mutation, const PropsParserContext &propsParserContext) const; From 4b3098723cd57300e06df5114f72ef926df2bedf Mon Sep 17 00:00:00 2001 From: Ngoc Le Date: Sat, 22 Aug 2026 23:38:44 +0700 Subject: [PATCH 2/2] docs(Reanimated): add changelog entry --- packages/react-native-reanimated/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-native-reanimated/CHANGELOG.md b/packages/react-native-reanimated/CHANGELOG.md index 68ba33ec6ab8..2190304b9d25 100644 --- a/packages/react-native-reanimated/CHANGELOG.md +++ b/packages/react-native-reanimated/CHANGELOG.md @@ -12,6 +12,7 @@ ### 🐛 Bug fixes +- Fix layout changes made during entering animations being overwritten by stale animation frames. ([#10382](https://github.com/software-mansion/react-native-reanimated/pull/10382) by [@ngocdevv](https://github.com/ngocdevv)) - Fix other window-relative layout animations not moving on iOS when Reanimated initializes after the surface is laid out: read the window size from the base revision when the Layout Animations Proxy attaches. ([#10362](https://github.com/software-mansion/react-native-reanimated/pull/10362) by [@pawicao](https://github.com/pawicao)) - Fix the predefined `ease` easing function using `cubicBezier(0.25, 0.1, 0.25, 0.1)` instead of the spec-defined `cubic-bezier(0.25, 0.1, 0.25, 1)`. ([#10353](https://github.com/software-mansion/react-native-reanimated/pull/10353) by [@tjzel](https://github.com/tjzel)) - Fix text losing its trailing word on Android after a CSS `fontSize` transition. ([#10342](https://github.com/software-mansion/react-native-reanimated/pull/10342) by [@MatiPl01](https://github.com/MatiPl01))