diff --git a/example/__tests__/nitro.views.harness.tsx b/example/__tests__/nitro.views.harness.tsx index 120bbef9e..4e169e13b 100644 --- a/example/__tests__/nitro.views.harness.tsx +++ b/example/__tests__/nitro.views.harness.tsx @@ -423,6 +423,77 @@ describe('TestView', () => { expect(view.getNativeDefaultValueSetterCallCount()).toBe(2) }) + it('only brackets transactions that deliver Nitro props with beforeUpdate/afterUpdate', async () => { + const viewRef = deferred() + const stableHybridRef = callback((view: TestViewRef) => + viewRef.resolve(view) + ) + const stableSomeCallback = callback(fn()) + const renderResult = await render( + // @ts-expect-error TypeScript requires TestView's props, but plain-JS + // consumers can omit them all at runtime - no Nitro props are delivered. + , + { timeout: RENDER_TIMEOUT } + ) + + await renderResult.rerender( + + ) + + const view = await viewRef.promise + // The empty mount delivered no Nitro props, so only the second render + // was a props transaction. + expect(view.getBeforeUpdateCount()).toBe(1) + expect(view.getAfterUpdateCount()).toBe(1) + + const resizedLayout = deferred() + await renderResult.rerender( + + resizedLayout.resolve(nativeEvent.layout) + } + /> + ) + + const reportedResizedLayout = await resizedLayout.promise + expect(reportedResizedLayout.width).toBeCloseTo(RESIZED_SIZE.width, 0) + expect(reportedResizedLayout.height).toBeCloseTo(RESIZED_SIZE.height, 0) + // A style-only resize changes no Nitro props - not a props transaction. + expect(view.getBeforeUpdateCount()).toBe(1) + expect(view.getAfterUpdateCount()).toBe(1) + + await renderResult.rerender( + + ) + + expect(view.isBlue).toBe(true) + expect(view.getBeforeUpdateCount()).toBe(2) + expect(view.getAfterUpdateCount()).toBe(2) + }) + it('unmounts and creates a fresh native view when remounted', async () => { const firstRef = deferred() const renderResult = await render( diff --git a/packages/react-native-nitro-test/android/src/main/java/com/margelo/nitro/test/HybridTestView.kt b/packages/react-native-nitro-test/android/src/main/java/com/margelo/nitro/test/HybridTestView.kt index 8b6141cad..59ccc0a6f 100644 --- a/packages/react-native-nitro-test/android/src/main/java/com/margelo/nitro/test/HybridTestView.kt +++ b/packages/react-native-nitro-test/android/src/main/java/com/margelo/nitro/test/HybridTestView.kt @@ -16,6 +16,8 @@ class HybridTestView( private var onDropViewCount = 0.0 private var isBlueSetterCallCount = 0.0 private var nativeDefaultValueSetterCallCount = 0.0 + private var beforeUpdateCount = 0.0 + private var afterUpdateCount = 0.0 // Props override var isBlue: Boolean = false @@ -41,6 +43,18 @@ class HybridTestView( override fun getNativeDefaultValueSetterCallCount(): Double = nativeDefaultValueSetterCallCount + override fun getBeforeUpdateCount(): Double = beforeUpdateCount + + override fun getAfterUpdateCount(): Double = afterUpdateCount + + override fun beforeUpdate() { + beforeUpdateCount += 1 + } + + override fun afterUpdate() { + afterUpdateCount += 1 + } + override fun someMethod() { hasBeenCalled = true someCallback() diff --git a/packages/react-native-nitro-test/ios/HybridTestView.swift b/packages/react-native-nitro-test/ios/HybridTestView.swift index 571a5dbaf..3d7e0b41a 100644 --- a/packages/react-native-nitro-test/ios/HybridTestView.swift +++ b/packages/react-native-nitro-test/ios/HybridTestView.swift @@ -14,6 +14,8 @@ class HybridTestView: HybridTestViewSpec { private var onDropViewCount: Double = 0 private var isBlueSetterCallCount: Double = 0 private var nativeDefaultValueSetterCallCount: Double = 0 + private var beforeUpdateCount: Double = 0 + private var afterUpdateCount: Double = 0 // Props var isBlue: Bool = false { @@ -44,6 +46,22 @@ class HybridTestView: HybridTestViewSpec { return nativeDefaultValueSetterCallCount } + func getBeforeUpdateCount() throws -> Double { + return beforeUpdateCount + } + + func getAfterUpdateCount() throws -> Double { + return afterUpdateCount + } + + func beforeUpdate() { + beforeUpdateCount += 1 + } + + func afterUpdate() { + afterUpdateCount += 1 + } + func someMethod() throws { hasBeenCalled = true someCallback() diff --git a/packages/react-native-nitro-test/nitrogen/generated/android/c++/JHybridTestViewSpec.cpp b/packages/react-native-nitro-test/nitrogen/generated/android/c++/JHybridTestViewSpec.cpp index e5481d155..af21c77ed 100644 --- a/packages/react-native-nitro-test/nitrogen/generated/android/c++/JHybridTestViewSpec.cpp +++ b/packages/react-native-nitro-test/nitrogen/generated/android/c++/JHybridTestViewSpec.cpp @@ -117,6 +117,16 @@ namespace margelo::nitro::test { auto __result = method(_javaPart); return __result; } + double JHybridTestViewSpec::getBeforeUpdateCount() { + static const auto method = _javaPart->javaClassStatic()->getMethod("getBeforeUpdateCount"); + auto __result = method(_javaPart); + return __result; + } + double JHybridTestViewSpec::getAfterUpdateCount() { + static const auto method = _javaPart->javaClassStatic()->getMethod("getAfterUpdateCount"); + auto __result = method(_javaPart); + return __result; + } void JHybridTestViewSpec::someMethod() { static const auto method = _javaPart->javaClassStatic()->getMethod("someMethod"); method(_javaPart); diff --git a/packages/react-native-nitro-test/nitrogen/generated/android/c++/JHybridTestViewSpec.hpp b/packages/react-native-nitro-test/nitrogen/generated/android/c++/JHybridTestViewSpec.hpp index 55dba01e7..a3ec61f50 100644 --- a/packages/react-native-nitro-test/nitrogen/generated/android/c++/JHybridTestViewSpec.hpp +++ b/packages/react-native-nitro-test/nitrogen/generated/android/c++/JHybridTestViewSpec.hpp @@ -66,6 +66,8 @@ namespace margelo::nitro::test { double getOnDropViewCount() override; double getIsBlueSetterCallCount() override; double getNativeDefaultValueSetterCallCount() override; + double getBeforeUpdateCount() override; + double getAfterUpdateCount() override; void someMethod() override; private: diff --git a/packages/react-native-nitro-test/nitrogen/generated/android/kotlin/com/margelo/nitro/test/HybridTestViewSpec.kt b/packages/react-native-nitro-test/nitrogen/generated/android/kotlin/com/margelo/nitro/test/HybridTestViewSpec.kt index 250ed4c20..6762537ec 100644 --- a/packages/react-native-nitro-test/nitrogen/generated/android/kotlin/com/margelo/nitro/test/HybridTestViewSpec.kt +++ b/packages/react-native-nitro-test/nitrogen/generated/android/kotlin/com/margelo/nitro/test/HybridTestViewSpec.kt @@ -78,6 +78,14 @@ abstract class HybridTestViewSpec: HybridView() { @Keep abstract fun getNativeDefaultValueSetterCallCount(): Double + @DoNotStrip + @Keep + abstract fun getBeforeUpdateCount(): Double + + @DoNotStrip + @Keep + abstract fun getAfterUpdateCount(): Double + @DoNotStrip @Keep abstract fun someMethod(): Unit diff --git a/packages/react-native-nitro-test/nitrogen/generated/ios/c++/HybridTestViewSpecSwift.hpp b/packages/react-native-nitro-test/nitrogen/generated/ios/c++/HybridTestViewSpecSwift.hpp index e963b6927..0871c9c4e 100644 --- a/packages/react-native-nitro-test/nitrogen/generated/ios/c++/HybridTestViewSpecSwift.hpp +++ b/packages/react-native-nitro-test/nitrogen/generated/ios/c++/HybridTestViewSpecSwift.hpp @@ -125,6 +125,22 @@ namespace margelo::nitro::test { auto __value = std::move(__result.value()); return __value; } + inline double getBeforeUpdateCount() override { + auto __result = _swiftPart.getBeforeUpdateCount(); + if (__result.hasError()) [[unlikely]] { + std::rethrow_exception(__result.error()); + } + auto __value = std::move(__result.value()); + return __value; + } + inline double getAfterUpdateCount() override { + auto __result = _swiftPart.getAfterUpdateCount(); + if (__result.hasError()) [[unlikely]] { + std::rethrow_exception(__result.error()); + } + auto __value = std::move(__result.value()); + return __value; + } inline void someMethod() override { auto __result = _swiftPart.someMethod(); if (__result.hasError()) [[unlikely]] { diff --git a/packages/react-native-nitro-test/nitrogen/generated/ios/swift/HybridTestViewSpec.swift b/packages/react-native-nitro-test/nitrogen/generated/ios/swift/HybridTestViewSpec.swift index 4a8d18de8..48e266a6c 100644 --- a/packages/react-native-nitro-test/nitrogen/generated/ios/swift/HybridTestViewSpec.swift +++ b/packages/react-native-nitro-test/nitrogen/generated/ios/swift/HybridTestViewSpec.swift @@ -20,6 +20,8 @@ public protocol HybridTestViewSpec_protocol: HybridObject, HybridView { func getOnDropViewCount() throws -> Double func getIsBlueSetterCallCount() throws -> Double func getNativeDefaultValueSetterCallCount() throws -> Double + func getBeforeUpdateCount() throws -> Double + func getAfterUpdateCount() throws -> Double func someMethod() throws -> Void } diff --git a/packages/react-native-nitro-test/nitrogen/generated/ios/swift/HybridTestViewSpec_cxx.swift b/packages/react-native-nitro-test/nitrogen/generated/ios/swift/HybridTestViewSpec_cxx.swift index cb34f0536..c2deeaa21 100644 --- a/packages/react-native-nitro-test/nitrogen/generated/ios/swift/HybridTestViewSpec_cxx.swift +++ b/packages/react-native-nitro-test/nitrogen/generated/ios/swift/HybridTestViewSpec_cxx.swift @@ -234,6 +234,30 @@ open class HybridTestViewSpec_cxx { } } + @inline(__always) + public final func getBeforeUpdateCount() -> bridge.Result_double_ { + do { + let __result = try self.__implementation.getBeforeUpdateCount() + let __resultCpp = __result + return bridge.create_Result_double_(__resultCpp) + } catch (let __error) { + let __exceptionPtr = __error.toCpp() + return bridge.create_Result_double_(__exceptionPtr) + } + } + + @inline(__always) + public final func getAfterUpdateCount() -> bridge.Result_double_ { + do { + let __result = try self.__implementation.getAfterUpdateCount() + let __resultCpp = __result + return bridge.create_Result_double_(__resultCpp) + } catch (let __error) { + let __exceptionPtr = __error.toCpp() + return bridge.create_Result_double_(__exceptionPtr) + } + } + @inline(__always) public final func someMethod() -> bridge.Result_void_ { do { diff --git a/packages/react-native-nitro-test/nitrogen/generated/shared/c++/HybridTestViewSpec.cpp b/packages/react-native-nitro-test/nitrogen/generated/shared/c++/HybridTestViewSpec.cpp index 06e2f8fd9..beb62e29a 100644 --- a/packages/react-native-nitro-test/nitrogen/generated/shared/c++/HybridTestViewSpec.cpp +++ b/packages/react-native-nitro-test/nitrogen/generated/shared/c++/HybridTestViewSpec.cpp @@ -27,6 +27,8 @@ namespace margelo::nitro::test { prototype.registerHybridMethod("getOnDropViewCount", &HybridTestViewSpec::getOnDropViewCount); prototype.registerHybridMethod("getIsBlueSetterCallCount", &HybridTestViewSpec::getIsBlueSetterCallCount); prototype.registerHybridMethod("getNativeDefaultValueSetterCallCount", &HybridTestViewSpec::getNativeDefaultValueSetterCallCount); + prototype.registerHybridMethod("getBeforeUpdateCount", &HybridTestViewSpec::getBeforeUpdateCount); + prototype.registerHybridMethod("getAfterUpdateCount", &HybridTestViewSpec::getAfterUpdateCount); prototype.registerHybridMethod("someMethod", &HybridTestViewSpec::someMethod); }); } diff --git a/packages/react-native-nitro-test/nitrogen/generated/shared/c++/HybridTestViewSpec.hpp b/packages/react-native-nitro-test/nitrogen/generated/shared/c++/HybridTestViewSpec.hpp index b51d5c0fe..ac02d25a3 100644 --- a/packages/react-native-nitro-test/nitrogen/generated/shared/c++/HybridTestViewSpec.hpp +++ b/packages/react-native-nitro-test/nitrogen/generated/shared/c++/HybridTestViewSpec.hpp @@ -63,6 +63,8 @@ namespace margelo::nitro::test { virtual double getOnDropViewCount() = 0; virtual double getIsBlueSetterCallCount() = 0; virtual double getNativeDefaultValueSetterCallCount() = 0; + virtual double getBeforeUpdateCount() = 0; + virtual double getAfterUpdateCount() = 0; virtual void someMethod() = 0; protected: diff --git a/packages/react-native-nitro-test/src/specs/TestView.nitro.ts b/packages/react-native-nitro-test/src/specs/TestView.nitro.ts index 857ba67d1..3e4a396d2 100644 --- a/packages/react-native-nitro-test/src/specs/TestView.nitro.ts +++ b/packages/react-native-nitro-test/src/specs/TestView.nitro.ts @@ -17,6 +17,8 @@ export interface TestViewMethods extends HybridViewMethods { getOnDropViewCount(): number getIsBlueSetterCallCount(): number getNativeDefaultValueSetterCallCount(): number + getBeforeUpdateCount(): number + getAfterUpdateCount(): number someMethod(): void }