diff --git a/React/Fabric/RCTScheduler.mm b/React/Fabric/RCTScheduler.mm index 9de730d92c0..228e92b8a7d 100644 --- a/React/Fabric/RCTScheduler.mm +++ b/React/Fabric/RCTScheduler.mm @@ -30,10 +30,19 @@ class SchedulerDelegateProxy : public SchedulerDelegate { [scheduler.delegate schedulerDidFinishTransaction:mountingCoordinator]; } - void schedulerDidRequestPreliminaryViewAllocation(SurfaceId surfaceId, const ShadowView &shadowView) override + void schedulerDidRequestPreliminaryViewAllocation(SurfaceId surfaceId, const ShadowNode &shadowNode) override { // Does nothing. - // Preemptive allocation of native views on iOS does not require this call. + // This delegate method is not currently used on iOS. + } + + void schedulerDidCloneShadowNode( + SurfaceId surfaceId, + const ShadowNode &oldShadowNode, + const ShadowNode &newShadowNode) override + { + // Does nothing. + // This delegate method is not currently used on iOS. } void schedulerDidDispatchCommand( diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp index 73e43c2a18b..d5fd9ca7fab 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp @@ -1128,13 +1128,9 @@ void Binding::driveCxxAnimations() { scheduler_->animationTick(); } -void Binding::schedulerDidRequestPreliminaryViewAllocation( +void Binding::preallocateShadowView( const SurfaceId surfaceId, const ShadowView &shadowView) { - if (disablePreallocateViews_) { - return; - } - jni::global_ref localJavaUIManager = getJavaUIManager(); if (!localJavaUIManager) { LOG(ERROR) @@ -1144,11 +1140,6 @@ void Binding::schedulerDidRequestPreliminaryViewAllocation( bool isLayoutableShadowNode = shadowView.layoutMetrics != EmptyLayoutMetrics; - if (disableVirtualNodePreallocation_ && - !shadowView.traits.check(ShadowNodeTraits::Trait::FormsView)) { - return; - } - static auto preallocateView = jni::findClassStatic(Binding::UIManagerJavaDescriptor) ->getMethodrevision != 1) { + return; + } + if (oldShadowNode.getProps()->revision != 0) { + return; + } + + // If the new node is concrete and the old wasn't, we can preallocate + if (!oldShadowNode.getTraits().check(ShadowNodeTraits::Trait::FormsView) && + newShadowNode.getTraits().check(ShadowNodeTraits::Trait::FormsView)) { + auto shadowView = ShadowView(newShadowNode); + preallocateShadowView(surfaceId, shadowView); + } +} + void Binding::schedulerDidDispatchCommand( const ShadowView &shadowView, std::string const &commandName, diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h index df0aeeb45aa..79b38d9bb2e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h @@ -135,9 +135,18 @@ class Binding : public jni::HybridClass, void schedulerDidFinishTransaction( MountingCoordinator::Shared const &mountingCoordinator) override; + void preallocateShadowView( + const SurfaceId surfaceId, + const ShadowView &shadowView); + void schedulerDidRequestPreliminaryViewAllocation( const SurfaceId surfaceId, - const ShadowView &shadowView) override; + const ShadowNode &shadowNode) override; + + void schedulerDidCloneShadowNode( + SurfaceId surfaceId, + const ShadowNode &oldShadowNode, + const ShadowNode &newShadowNode) override; void schedulerDidDispatchCommand( const ShadowView &shadowView, diff --git a/ReactCommon/react/renderer/scheduler/Scheduler.cpp b/ReactCommon/react/renderer/scheduler/Scheduler.cpp index 2ea92bb1994..b73db19bf98 100644 --- a/ReactCommon/react/renderer/scheduler/Scheduler.cpp +++ b/ReactCommon/react/renderer/scheduler/Scheduler.cpp @@ -287,14 +287,23 @@ void Scheduler::uiManagerDidFinishTransaction( delegate_->schedulerDidFinishTransaction(mountingCoordinator); } } -void Scheduler::uiManagerDidCreateShadowNode( - const ShadowNode::Shared &shadowNode) { +void Scheduler::uiManagerDidCreateShadowNode(const ShadowNode &shadowNode) { SystraceSection s("Scheduler::uiManagerDidCreateShadowNode"); if (delegate_) { - auto shadowView = ShadowView(*shadowNode); delegate_->schedulerDidRequestPreliminaryViewAllocation( - shadowNode->getSurfaceId(), shadowView); + shadowNode.getSurfaceId(), shadowNode); + } +} + +void Scheduler::uiManagerDidCloneShadowNode( + const ShadowNode &oldShadowNode, + const ShadowNode &newShadowNode) { + SystraceSection s("Scheduler::uiManagerDidCloneShadowNode"); + + if (delegate_) { + delegate_->schedulerDidCloneShadowNode( + newShadowNode.getSurfaceId(), oldShadowNode, newShadowNode); } } diff --git a/ReactCommon/react/renderer/scheduler/Scheduler.h b/ReactCommon/react/renderer/scheduler/Scheduler.h index 03c8f65d2ea..f0f72ff53d2 100644 --- a/ReactCommon/react/renderer/scheduler/Scheduler.h +++ b/ReactCommon/react/renderer/scheduler/Scheduler.h @@ -83,8 +83,10 @@ class Scheduler final : public UIManagerDelegate { void uiManagerDidFinishTransaction( MountingCoordinator::Shared const &mountingCoordinator) override; - void uiManagerDidCreateShadowNode( - const ShadowNode::Shared &shadowNode) override; + void uiManagerDidCreateShadowNode(const ShadowNode &shadowNode) override; + void uiManagerDidCloneShadowNode( + const ShadowNode &oldShadowNode, + const ShadowNode &newShadowNode) override; void uiManagerDidDispatchCommand( const ShadowNode::Shared &shadowNode, std::string const &commandName, diff --git a/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h b/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h index 33e247c631b..cfd41c5d30d 100644 --- a/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h +++ b/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h @@ -34,7 +34,15 @@ class SchedulerDelegate { */ virtual void schedulerDidRequestPreliminaryViewAllocation( SurfaceId surfaceId, - const ShadowView &shadowView) = 0; + const ShadowNode &shadowView) = 0; + + /* + * Called right after a ShadowNode is cloned. + */ + virtual void schedulerDidCloneShadowNode( + SurfaceId surfaceId, + const ShadowNode &oldShadowNode, + const ShadowNode &newShadowNode) = 0; virtual void schedulerDidDispatchCommand( const ShadowView &shadowView, diff --git a/ReactCommon/react/renderer/uimanager/UIManager.cpp b/ReactCommon/react/renderer/uimanager/UIManager.cpp index a1c9d3612b5..a64ecf7446a 100644 --- a/ReactCommon/react/renderer/uimanager/UIManager.cpp +++ b/ReactCommon/react/renderer/uimanager/UIManager.cpp @@ -73,7 +73,7 @@ SharedShadowNode UIManager::createNode( family); if (delegate_) { - delegate_->uiManagerDidCreateShadowNode(shadowNode); + delegate_->uiManagerDidCreateShadowNode(*shadowNode.get()); } if (leakChecker_) { leakChecker_->uiManagerDidCreateShadowNodeFamily(family); @@ -99,6 +99,11 @@ SharedShadowNode UIManager::cloneNode( /* .children = */ children, }); + if (delegate_) { + delegate_->uiManagerDidCloneShadowNode( + *shadowNode.get(), *clonedShadowNode.get()); + } + return clonedShadowNode; } diff --git a/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h b/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h index 57b0dccfa32..91d8bf55107 100644 --- a/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h +++ b/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h @@ -30,8 +30,16 @@ class UIManagerDelegate { * might use this to optimistically allocate a new native view * instances. */ - virtual void uiManagerDidCreateShadowNode( - const ShadowNode::Shared &shadowNode) = 0; + virtual void uiManagerDidCreateShadowNode(const ShadowNode &shadowNode) = 0; + + /* + * Called each time when UIManager clones a Shadow Node. Receiver + * might use this to optimistically allocate a new native view + * instances. + */ + virtual void uiManagerDidCloneShadowNode( + const ShadowNode &oldShadowNode, + const ShadowNode &newShadowNode) = 0; /* * Called when UIManager wants to dispatch a command to the mounting layer.