From bae63d492fa8254547453229f28332f08e8b881c Mon Sep 17 00:00:00 2001 From: Eric Rozell Date: Wed, 26 Jul 2023 13:14:59 -0700 Subject: [PATCH] Break circular dependency between renderer/core and renderer/components/view (#38637) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/38637 ComponentDescriptor and ConcreteComponentDescriptor expose a virtual method to interpolate props for LayoutAnimation. The implementation of this virtual method in ConcreteComponentDescriptor calls ViewPropsInterpolation, creating a circular dependency between react/renderer/core and react/renderer/components/view. To break this circular dependency, this change lifts the props interpolation functionality out of ComponentDescriptor into LayoutAnimationKeyFrameManager. Please note, while this is technically a "breaking" change, as component descriptors for 3p components may have overridden this method, it's not supported because LayoutAnimation only works on View props. ## Changelog: [General] [Breaking] - Remove interpolateProps functionality from ComponentDescriptor to fix circular dependency between react/renderer/core and react/renderer/components/view Reviewed By: christophpurrer Differential Revision: D47797967 fbshipit-source-id: 5285da7cc9de29f21ce14c96b850a3c58c579e94 --- .../LayoutAnimationKeyFrameManager.cpp | 38 ++++++++++++++++++- .../LayoutAnimationKeyFrameManager.h | 10 +++++ .../react/renderer/core/ComponentDescriptor.h | 10 ----- .../core/ConcreteComponentDescriptor.h | 25 ------------ 4 files changed, 46 insertions(+), 37 deletions(-) diff --git a/packages/react-native/ReactCommon/react/renderer/animations/LayoutAnimationKeyFrameManager.cpp b/packages/react-native/ReactCommon/react/renderer/animations/LayoutAnimationKeyFrameManager.cpp index 71df612c864c89..1ae5ae8f37087a 100644 --- a/packages/react-native/ReactCommon/react/renderer/animations/LayoutAnimationKeyFrameManager.cpp +++ b/packages/react-native/ReactCommon/react/renderer/animations/LayoutAnimationKeyFrameManager.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -1152,8 +1153,13 @@ ShadowView LayoutAnimationKeyFrameManager::createInterpolatedShadowView( // Animate opacity or scale/transform PropsParserContext propsParserContext{ finalView.surfaceId, *contextContainer_}; - mutatedShadowView.props = componentDescriptor.interpolateProps( - propsParserContext, progress, startingView.props, finalView.props); + mutatedShadowView.props = interpolateProps( + componentDescriptor, + propsParserContext, + progress, + startingView.props, + finalView.props); + react_native_assert(mutatedShadowView.props != nullptr); if (mutatedShadowView.props == nullptr) { return finalView; @@ -1656,4 +1662,32 @@ void LayoutAnimationKeyFrameManager::deleteAnimationsForStoppedSurfaces() } } +Props::Shared LayoutAnimationKeyFrameManager::interpolateProps( + const ComponentDescriptor &componentDescriptor, + const PropsParserContext &context, + Float animationProgress, + const Props::Shared &props, + const Props::Shared &newProps) const { +#ifdef ANDROID + // On Android only, the merged props should have the same RawProps as the + // final props struct + Props::Shared interpolatedPropsShared = + (newProps != nullptr + ? componentDescriptor.cloneProps( + context, newProps, newProps->rawProps) + : componentDescriptor.cloneProps(context, newProps, {})); +#else + Props::Shared interpolatedPropsShared = + componentDescriptor.cloneProps(context, newProps, {}); +#endif + + if (componentDescriptor.getTraits().check( + ShadowNodeTraits::Trait::ViewKind)) { + interpolateViewProps( + animationProgress, props, newProps, interpolatedPropsShared); + } + + return interpolatedPropsShared; +}; + } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/animations/LayoutAnimationKeyFrameManager.h b/packages/react-native/ReactCommon/react/renderer/animations/LayoutAnimationKeyFrameManager.h index 6d0d541c1cf861..7e5937ce21acb9 100644 --- a/packages/react-native/ReactCommon/react/renderer/animations/LayoutAnimationKeyFrameManager.h +++ b/packages/react-native/ReactCommon/react/renderer/animations/LayoutAnimationKeyFrameManager.h @@ -173,6 +173,16 @@ class LayoutAnimationKeyFrameManager : public UIManagerAnimationDelegate, void simulateImagePropsMemoryAccess( ShadowViewMutationList const &mutations) const; + + /** + * Interpolates the props values. + */ + Props::Shared interpolateProps( + const ComponentDescriptor &componentDescriptor, + const PropsParserContext &context, + Float animationProgress, + const Props::Shared &props, + const Props::Shared &newProps) const; }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/core/ComponentDescriptor.h b/packages/react-native/ReactCommon/react/renderer/core/ComponentDescriptor.h index 8b3fabe9e2e27d..bf0cdd731db182 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ComponentDescriptor.h +++ b/packages/react-native/ReactCommon/react/renderer/core/ComponentDescriptor.h @@ -108,16 +108,6 @@ class ComponentDescriptor { const Props::Shared &props, const RawProps &rawProps) const = 0; - /* - * Creates a new `Props` of a particular type with all values interpolated - * between `props` and `newProps`. - */ - virtual Props::Shared interpolateProps( - const PropsParserContext &context, - Float animationProgress, - const Props::Shared &props, - const Props::Shared &newProps) const = 0; - /* * Create an initial State object that represents (and contains) an initial * State's data which can be constructed based on initial Props. diff --git a/packages/react-native/ReactCommon/react/renderer/core/ConcreteComponentDescriptor.h b/packages/react-native/ReactCommon/react/renderer/core/ConcreteComponentDescriptor.h index 01ea9b1603ba87..b5313f4aa2d586 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ConcreteComponentDescriptor.h +++ b/packages/react-native/ReactCommon/react/renderer/core/ConcreteComponentDescriptor.h @@ -11,7 +11,6 @@ #include #include -#include #include #include #include @@ -125,30 +124,6 @@ class ConcreteComponentDescriptor : public ComponentDescriptor { return shadowNodeProps; }; - Props::Shared interpolateProps( - const PropsParserContext &context, - Float animationProgress, - const Props::Shared &props, - const Props::Shared &newProps) const override { -#ifdef ANDROID - // On Android only, the merged props should have the same RawProps as the - // final props struct - Props::Shared interpolatedPropsShared = - (newProps != nullptr ? cloneProps(context, newProps, newProps->rawProps) - : cloneProps(context, newProps, {})); -#else - Props::Shared interpolatedPropsShared = cloneProps(context, newProps, {}); -#endif - - if (ConcreteShadowNode::BaseTraits().check( - ShadowNodeTraits::Trait::ViewKind)) { - interpolateViewProps( - animationProgress, props, newProps, interpolatedPropsShared); - } - - return interpolatedPropsShared; - }; - virtual State::Shared createInitialState( Props::Shared const &props, ShadowNodeFamily::Shared const &family) const override {