From 8772df9612268121061ab6f1e72b53920a2213f4 Mon Sep 17 00:00:00 2001 From: Marc Rousavy Date: Thu, 16 Jan 2025 02:03:02 +0100 Subject: [PATCH] feat: Add `beforeUpdate()` and `afterUpdate()` --- .../src/syntax/swift/SwiftHybridObjectBridge.ts | 10 ++++++++++ .../src/views/swift/SwiftHybridViewManager.ts | 8 ++++++++ .../ios/c++/views/HybridTestViewComponent.mm | 6 ++++++ .../ios/swift/HybridTestViewSpec_cxx.swift | 8 ++++++++ .../ios/views/HybridView.swift | 16 ++++++++++++++++ 5 files changed, 48 insertions(+) diff --git a/packages/nitrogen/src/syntax/swift/SwiftHybridObjectBridge.ts b/packages/nitrogen/src/syntax/swift/SwiftHybridObjectBridge.ts index 79315b6b8..b0a113093 100644 --- a/packages/nitrogen/src/syntax/swift/SwiftHybridObjectBridge.ts +++ b/packages/nitrogen/src/syntax/swift/SwiftHybridObjectBridge.ts @@ -56,6 +56,16 @@ export function createSwiftHybridObjectCxxBridge( public final func getView() -> UnsafeMutableRawPointer { return Unmanaged.passRetained(__implementation.view).toOpaque() } +`.trim(), + ` +public final func beforeUpdate() { + __implementation.beforeUpdate() +} + `.trim(), + ` +public final func afterUpdate() { + __implementation.afterUpdate() +} `.trim() ) } diff --git a/packages/nitrogen/src/views/swift/SwiftHybridViewManager.ts b/packages/nitrogen/src/views/swift/SwiftHybridViewManager.ts index 0339ab1c7..83f55e257 100644 --- a/packages/nitrogen/src/views/swift/SwiftHybridViewManager.ts +++ b/packages/nitrogen/src/views/swift/SwiftHybridViewManager.ts @@ -94,9 +94,11 @@ using namespace ${namespace}::views; - (void) updateView { // 1. Get Swift part ${swiftNamespace}::${HybridTSpecCxx}& swiftPart = _hybridView->getSwiftPart(); + // 2. Get UIView* void* viewUnsafe = swiftPart.getView(); UIView* view = (__bridge_transfer UIView*) viewUnsafe; + // 3. Update RCTViewComponentView's [contentView] [self setContentView:view]; } @@ -107,8 +109,14 @@ using namespace ${namespace}::views; const auto& newViewPropsConst = *std::static_pointer_cast<${propsClassName} const>(props); auto& newViewProps = const_cast<${propsClassName}&>(newViewPropsConst); ${swiftNamespace}::${HybridTSpecCxx}& swiftPart = _hybridView->getSwiftPart(); + // 2. Update each prop + swiftPart.beforeUpdate(); + ${indent(propAssignments.join('\n'), ' ')} + + swiftPart.afterUpdate(); + // 3. Continue in base class [super updateProps:props oldProps:oldProps]; } diff --git a/packages/react-native-nitro-image/nitrogen/generated/ios/c++/views/HybridTestViewComponent.mm b/packages/react-native-nitro-image/nitrogen/generated/ios/c++/views/HybridTestViewComponent.mm index 32cbfba41..63a0a45f2 100644 --- a/packages/react-native-nitro-image/nitrogen/generated/ios/c++/views/HybridTestViewComponent.mm +++ b/packages/react-native-nitro-image/nitrogen/generated/ios/c++/views/HybridTestViewComponent.mm @@ -66,7 +66,10 @@ - (void) updateProps:(const react::Props::Shared&)props const auto& newViewPropsConst = *std::static_pointer_cast(props); auto& newViewProps = const_cast(newViewPropsConst); NitroImage::HybridTestViewSpec_cxx& swiftPart = _hybridView->getSwiftPart(); + // 2. Update each prop + swiftPart.beforeUpdate(); + if (newViewProps.someProp.isDirty) { swiftPart.setSomeProp(newViewProps.someProp.value); newViewProps.someProp.isDirty = false; @@ -75,6 +78,9 @@ - (void) updateProps:(const react::Props::Shared&)props swiftPart.setSomeCallback(newViewProps.someCallback.value); newViewProps.someCallback.isDirty = false; } + + swiftPart.afterUpdate(); + // 3. Continue in base class [super updateProps:props oldProps:oldProps]; } diff --git a/packages/react-native-nitro-image/nitrogen/generated/ios/swift/HybridTestViewSpec_cxx.swift b/packages/react-native-nitro-image/nitrogen/generated/ios/swift/HybridTestViewSpec_cxx.swift index 1794ba9c4..50f5d5365 100644 --- a/packages/react-native-nitro-image/nitrogen/generated/ios/swift/HybridTestViewSpec_cxx.swift +++ b/packages/react-native-nitro-image/nitrogen/generated/ios/swift/HybridTestViewSpec_cxx.swift @@ -143,4 +143,12 @@ public class HybridTestViewSpec_cxx { public final func getView() -> UnsafeMutableRawPointer { return Unmanaged.passRetained(__implementation.view).toOpaque() } + + public final func beforeUpdate() { + __implementation.beforeUpdate() + } + + public final func afterUpdate() { + __implementation.afterUpdate() + } } diff --git a/packages/react-native-nitro-modules/ios/views/HybridView.swift b/packages/react-native-nitro-modules/ios/views/HybridView.swift index e712f6839..d5c503292 100644 --- a/packages/react-native-nitro-modules/ios/views/HybridView.swift +++ b/packages/react-native-nitro-modules/ios/views/HybridView.swift @@ -20,6 +20,22 @@ public protocol HybridView: HybridObject { * This value should not change during the lifetime of this ``HybridView``. */ var view: UIView { get } + + /** + * Called right before updating props. + * React props are updated in a single batch/transaction. + */ + func beforeUpdate() + /** + * Called right after updating props. + * React props are updated in a single batch/transaction. + */ + func afterUpdate() +} + +public extension HybridView { + func beforeUpdate() { /* noop */ } + func afterUpdate() { /* noop */ } } #endif