diff --git a/React/Fabric/Mounting/RCTMountingManager.h b/React/Fabric/Mounting/RCTMountingManager.h index d30d297e366749..d7dd3ed82a5abc 100644 --- a/React/Fabric/Mounting/RCTMountingManager.h +++ b/React/Fabric/Mounting/RCTMountingManager.h @@ -10,6 +10,7 @@ #import #import #import +#import #import #import #import @@ -55,6 +56,13 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)dispatchCommand:(ReactTag)reactTag commandName:(NSString *)commandName args:(NSArray *)args; +/** + * Set props on native view directly. It is a performance shortcut that skips render pipeline. + * This is a backport of setNativeProps from the old architecture and will be removed in the future. + * Can be called from any thread. + */ +- (void)setNativeProps_DEPRECATED:(ReactTag)reactTag withProps:(facebook::react::Props::Shared)props; + /** * Dispatch an accessibility event to be performed on the main thread. * Can be called from any thread. diff --git a/React/Fabric/Mounting/RCTMountingManager.mm b/React/Fabric/Mounting/RCTMountingManager.mm index e950a62e0feb3b..10ded9c4b59752 100644 --- a/React/Fabric/Mounting/RCTMountingManager.mm +++ b/React/Fabric/Mounting/RCTMountingManager.mm @@ -225,11 +225,24 @@ - (void)dispatchCommand:(ReactTag)reactTag commandName:(NSString *)commandName a } RCTExecuteOnMainQueue(^{ - RCTAssertMainQueue(); [self synchronouslyDispatchCommandOnUIThread:reactTag commandName:commandName args:args]; }); } +- (void)setNativeProps_DEPRECATED:(ReactTag)reactTag withProps:(Props::Shared)props +{ + if (RCTIsMainQueue()) { + UIView *componentView = [_componentViewRegistry findComponentViewWithTag:reactTag]; + Props::Shared oldProps = [componentView props]; + [componentView updateProps:props oldProps:oldProps]; + [componentView finalizeUpdates:RNComponentViewUpdateMaskProps]; + return; + } + RCTExecuteOnMainQueue(^{ + [self setNativeProps_DEPRECATED:reactTag withProps:std::move(props)]; + }); +} + - (void)sendAccessibilityEvent:(ReactTag)reactTag eventType:(NSString *)eventType { if (RCTIsMainQueue()) { @@ -241,7 +254,6 @@ - (void)sendAccessibilityEvent:(ReactTag)reactTag eventType:(NSString *)eventTyp } RCTExecuteOnMainQueue(^{ - RCTAssertMainQueue(); [self synchronouslyDispatchAccessbilityEventOnUIThread:reactTag eventType:eventType]; }); } diff --git a/React/Fabric/RCTScheduler.h b/React/Fabric/RCTScheduler.h index bebc5fd90f0050..1a2bac49f82822 100644 --- a/React/Fabric/RCTScheduler.h +++ b/React/Fabric/RCTScheduler.h @@ -34,6 +34,9 @@ NS_ASSUME_NONNULL_BEGIN commandName:(std::string const &)commandName args:(folly::dynamic const &)args; +- (void)setNativeProps_DEPRECATED:(facebook::react::ShadowView const &)shadowView + withProps:(facebook::react::Props::Shared)props; + - (void)schedulerDidSendAccessibilityEvent:(facebook::react::ShadowView const &)shadowView eventType:(std::string const &)eventType; diff --git a/React/Fabric/RCTScheduler.mm b/React/Fabric/RCTScheduler.mm index 1b621d6b129ba2..3187732e6802c7 100644 --- a/React/Fabric/RCTScheduler.mm +++ b/React/Fabric/RCTScheduler.mm @@ -45,6 +45,12 @@ void schedulerDidDispatchCommand( [scheduler.delegate schedulerDidDispatchCommand:shadowView commandName:commandName args:args]; } + void setNativeProps_DEPRECATED(const ShadowView &shadowView, Props::Shared props) override + { + RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_; + [scheduler.delegate setNativeProps_DEPRECATED:shadowView withProps:std::move(props)]; + } + void schedulerDidSetIsJSResponder(ShadowView const &shadowView, bool isJSResponder, bool blockNativeResponder) override { diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm index 7d2ac388a72703..70ceefc10efaac 100644 --- a/React/Fabric/RCTSurfacePresenter.mm +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -372,6 +372,12 @@ - (void)schedulerDidDispatchCommand:(ShadowView const &)shadowView [_mountingManager dispatchCommand:tag commandName:commandStr args:argsArray]; } +- (void)setNativeProps_DEPRECATED:(ShadowView const &)shadowView withProps:(Props::Shared)props +{ + ReactTag tag = shadowView.tag; + [self->_mountingManager setNativeProps_DEPRECATED:tag withProps:props]; +} + - (void)schedulerDidSendAccessibilityEvent:(const facebook::react::ShadowView &)shadowView eventType:(const std::string &)eventType { diff --git a/ReactAndroid/src/main/jni/react/fabric/Binding.cpp b/ReactAndroid/src/main/jni/react/fabric/Binding.cpp index 296a61aafe34e9..e48202052a6d45 100644 --- a/ReactAndroid/src/main/jni/react/fabric/Binding.cpp +++ b/ReactAndroid/src/main/jni/react/fabric/Binding.cpp @@ -549,6 +549,12 @@ void Binding::schedulerDidDispatchCommand( mountingManager->dispatchCommand(shadowView, commandName, args); } +void Binding::setNativeProps_DEPRECATED( + const ShadowView &shadowView, + Props::Shared props) { + // TODO(T130729920): Add Android implementation for setNativeProps. +} + void Binding::schedulerDidSendAccessibilityEvent( const ShadowView &shadowView, std::string const &eventType) { diff --git a/ReactAndroid/src/main/jni/react/fabric/Binding.h b/ReactAndroid/src/main/jni/react/fabric/Binding.h index a5b47ebeff3a72..c1f4e9d6718e7a 100644 --- a/ReactAndroid/src/main/jni/react/fabric/Binding.h +++ b/ReactAndroid/src/main/jni/react/fabric/Binding.h @@ -107,6 +107,10 @@ class Binding : public jni::HybridClass, std::string const &commandName, folly::dynamic const &args) override; + void setNativeProps_DEPRECATED( + const ShadowView &shadowView, + Props::Shared props) override; + void schedulerDidSendAccessibilityEvent( const ShadowView &shadowView, std::string const &eventType) override; diff --git a/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp b/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp index 61deb7c607805a..4bc5bac4a971b0 100644 --- a/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp @@ -202,6 +202,7 @@ void YogaLayoutableShadowNode::adoptYogaChild(size_t index) { // react_native_assert(layoutableChildNode.yogaNode_.isDirty()); } else { // The child is owned by some other node, we need to clone that. + // TODO: At this point, React has wrong reference to the node. (T138668036) auto clonedChildNode = childNode.clone({}); auto &layoutableClonedChildNode = traitCast(*clonedChildNode); diff --git a/ReactCommon/react/renderer/core/DynamicPropsUtilities.cpp b/ReactCommon/react/renderer/core/DynamicPropsUtilities.cpp index 116a0a418f09de..ce379a47294814 100644 --- a/ReactCommon/react/renderer/core/DynamicPropsUtilities.cpp +++ b/ReactCommon/react/renderer/core/DynamicPropsUtilities.cpp @@ -8,6 +8,7 @@ #include "DynamicPropsUtilities.h" namespace facebook::react { + folly::dynamic mergeDynamicProps( folly::dynamic const &source, folly::dynamic const &patch) { @@ -30,4 +31,8 @@ folly::dynamic mergeDynamicProps( return result; } +RawProps mergeRawProps(folly::dynamic const &source, RawProps const &patch) { + return {mergeDynamicProps((folly::dynamic)source, (folly::dynamic)patch)}; +} + } // namespace facebook::react diff --git a/ReactCommon/react/renderer/core/DynamicPropsUtilities.h b/ReactCommon/react/renderer/core/DynamicPropsUtilities.h index d251f20b757031..bde7f84ed70fcd 100644 --- a/ReactCommon/react/renderer/core/DynamicPropsUtilities.h +++ b/ReactCommon/react/renderer/core/DynamicPropsUtilities.h @@ -8,13 +8,14 @@ #pragma once #include +#include -namespace facebook { -namespace react { +namespace facebook::react { folly::dynamic mergeDynamicProps( folly::dynamic const &source, folly::dynamic const &patch); -} // namespace react -} // namespace facebook +RawProps mergeRawProps(folly::dynamic const &source, RawProps const &patch); + +} // namespace facebook::react diff --git a/ReactCommon/react/renderer/core/ShadowNodeFamily.h b/ReactCommon/react/renderer/core/ShadowNodeFamily.h index a4ed371ff790c3..f907e1913b3dd0 100644 --- a/ReactCommon/react/renderer/core/ShadowNodeFamily.h +++ b/ReactCommon/react/renderer/core/ShadowNodeFamily.h @@ -86,6 +86,13 @@ class ShadowNodeFamily final { void dispatchRawState(StateUpdate &&stateUpdate, EventPriority priority) const; + /* + * Holds currently applied native props. `nullptr` if setNativeProps API is + * not used. It is used to backport setNativeProps API from the old + * architecture and will be removed in the future. + */ + mutable std::unique_ptr nativeProps_DEPRECATED; + private: friend ShadowNode; friend ShadowNodeFamilyFragment; diff --git a/ReactCommon/react/renderer/scheduler/Scheduler.cpp b/ReactCommon/react/renderer/scheduler/Scheduler.cpp index 656f7c852c979d..b9746e605fc0a7 100644 --- a/ReactCommon/react/renderer/scheduler/Scheduler.cpp +++ b/ReactCommon/react/renderer/scheduler/Scheduler.cpp @@ -321,6 +321,17 @@ void Scheduler::uiManagerDidDispatchCommand( } } +void Scheduler::setNativeProps_DEPRECATED( + const ShadowNode::Shared &shadowNode, + Props::Shared props) { + SystraceSection s("Scheduler::setNativeProps_DEPRECATED"); + + if (delegate_ != nullptr) { + auto shadowView = ShadowView(*shadowNode); + delegate_->setNativeProps_DEPRECATED(shadowView, std::move(props)); + } +} + void Scheduler::uiManagerDidSendAccessibilityEvent( const ShadowNode::Shared &shadowNode, std::string const &eventType) { diff --git a/ReactCommon/react/renderer/scheduler/Scheduler.h b/ReactCommon/react/renderer/scheduler/Scheduler.h index d42bfe802bb0a4..23199d4bff57c5 100644 --- a/ReactCommon/react/renderer/scheduler/Scheduler.h +++ b/ReactCommon/react/renderer/scheduler/Scheduler.h @@ -94,6 +94,9 @@ class Scheduler final : public UIManagerDelegate { const ShadowNode::Shared &shadowNode, std::string const &commandName, folly::dynamic const &args) override; + void setNativeProps_DEPRECATED( + const ShadowNode::Shared &shadowNode, + Props::Shared props) override; void uiManagerDidSendAccessibilityEvent( const ShadowNode::Shared &shadowNode, std::string const &eventType) override; diff --git a/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h b/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h index db36d2c04098cc..b1a44c4b1b48eb 100644 --- a/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h +++ b/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h @@ -13,8 +13,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { /* * Abstract class for Scheduler's delegate. @@ -41,6 +40,10 @@ class SchedulerDelegate { std::string const &commandName, folly::dynamic const &args) = 0; + virtual void setNativeProps_DEPRECATED( + const ShadowView &shadowView, + Props::Shared props) = 0; + virtual void schedulerDidSendAccessibilityEvent( const ShadowView &shadowView, std::string const &eventType) = 0; @@ -56,5 +59,4 @@ class SchedulerDelegate { virtual ~SchedulerDelegate() noexcept = default; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/ReactCommon/react/renderer/uimanager/UIManager.cpp b/ReactCommon/react/renderer/uimanager/UIManager.cpp index 37ec52dc3e4880..a6a11e5e6d1f9a 100644 --- a/ReactCommon/react/renderer/uimanager/UIManager.cpp +++ b/ReactCommon/react/renderer/uimanager/UIManager.cpp @@ -8,6 +8,7 @@ #include "UIManager.h" #include +#include #include #include #include @@ -109,14 +110,29 @@ ShadowNode::Shared UIManager::cloneNode( shadowNode.getFamily().getSurfaceId(), *contextContainer_.get()}; auto &componentDescriptor = shadowNode.getComponentDescriptor(); + auto &family = shadowNode.getFamily(); + auto props = ShadowNodeFragment::propsPlaceholder(); + + if (rawProps != nullptr) { + if (family.nativeProps_DEPRECATED != nullptr) { + family.nativeProps_DEPRECATED = + std::make_unique(mergeDynamicProps( + (folly::dynamic)*rawProps, *family.nativeProps_DEPRECATED)); + + props = componentDescriptor.cloneProps( + propsParserContext, + shadowNode.getProps(), + mergeRawProps(*family.nativeProps_DEPRECATED, *rawProps)); + } else { + props = componentDescriptor.cloneProps( + propsParserContext, shadowNode.getProps(), *rawProps); + } + } + auto clonedShadowNode = componentDescriptor.cloneShadowNode( shadowNode, { - /* .props = */ - rawProps != nullptr - ? componentDescriptor.cloneProps( - propsParserContext, shadowNode.getProps(), *rawProps) - : ShadowNodeFragment::propsPlaceholder(), + /* .props = */ props, /* .children = */ children, }); @@ -329,6 +345,34 @@ void UIManager::dispatchCommand( } } +void UIManager::setNativeProps_DEPRECATED( + ShadowNode::Shared const &shadowNode, + RawProps const &rawProps) const { + if (delegate_ != nullptr) { + auto &family = shadowNode->getFamily(); + if (family.nativeProps_DEPRECATED) { + family.nativeProps_DEPRECATED = + std::make_unique(mergeDynamicProps( + *family.nativeProps_DEPRECATED, (folly::dynamic)rawProps)); + } else { + family.nativeProps_DEPRECATED = + std::make_unique((folly::dynamic)rawProps); + } + + PropsParserContext propsParserContext{ + family.getSurfaceId(), *contextContainer_.get()}; + auto &componentDescriptor = + componentDescriptorRegistry_->at(shadowNode->getComponentHandle()); + + auto props = componentDescriptor.cloneProps( + propsParserContext, + getNewestCloneOfShadowNode(*shadowNode)->getProps(), + RawProps(*family.nativeProps_DEPRECATED)); + + delegate_->setNativeProps_DEPRECATED(shadowNode, std::move(props)); + } +} + void UIManager::sendAccessibilityEvent( const ShadowNode::Shared &shadowNode, std::string const &eventType) { diff --git a/ReactCommon/react/renderer/uimanager/UIManager.h b/ReactCommon/react/renderer/uimanager/UIManager.h index 00b64d252d2766..7e2d47776e0936 100644 --- a/ReactCommon/react/renderer/uimanager/UIManager.h +++ b/ReactCommon/react/renderer/uimanager/UIManager.h @@ -162,6 +162,10 @@ class UIManager final : public ShadowTreeDelegate { std::string const &commandName, folly::dynamic const &args) const; + void setNativeProps_DEPRECATED( + ShadowNode::Shared const &shadowNode, + RawProps const &rawProps) const; + void sendAccessibilityEvent( const ShadowNode::Shared &shadowNode, std::string const &eventType); diff --git a/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp b/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp index be8278e7dc459d..5bff9f775dddd8 100644 --- a/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp +++ b/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp @@ -501,6 +501,24 @@ jsi::Value UIManagerBinding::get( }); } + if (methodName == "setNativeProps") { + return jsi::Function::createFromHostFunction( + runtime, + name, + 2, + [uiManager]( + jsi::Runtime &runtime, + const jsi::Value &, + const jsi::Value *arguments, + size_t) -> jsi::Value { + uiManager->setNativeProps_DEPRECATED( + shadowNodeFromValue(runtime, arguments[0]), + RawProps(runtime, arguments[1])); + + return jsi::Value::undefined(); + }); + } + // Legacy API if (methodName == "measureLayout") { return jsi::Function::createFromHostFunction( diff --git a/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h b/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h index 77f1e4e3b62be4..6e4a97bcd36c04 100644 --- a/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h +++ b/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h @@ -40,6 +40,15 @@ class UIManagerDelegate { std::string const &commandName, folly::dynamic const &args) = 0; + /* + * Called when UIManager wants directly manipulate view on the mounting layer. + * This is a backport of setNativeProps from the old architecture and will be + * removed in the future. + */ + virtual void setNativeProps_DEPRECATED( + const ShadowNode::Shared &shadowNode, + Props::Shared props) = 0; + /* * Called when UIManager wants to dispatch some accessibility event * to the mounting layer. eventType is platform-specific and not all