diff --git a/ReactCommon/fabric/components/view/ViewEventEmitter.cpp b/ReactCommon/fabric/components/view/ViewEventEmitter.cpp index bcdb2c95290a0c..20693ec0faad59 100644 --- a/ReactCommon/fabric/components/view/ViewEventEmitter.cpp +++ b/ReactCommon/fabric/components/view/ViewEventEmitter.cpp @@ -35,6 +35,17 @@ void ViewEventEmitter::onAccessibilityEscape() const { #pragma mark - Layout void ViewEventEmitter::onLayout(const LayoutMetrics &layoutMetrics) const { + // Due to State Reconciliation, `onLayout` can be called potentially many + // times with identical layoutMetrics. Ensure that the JS event is only + // dispatched when the value changes. + auto lastLayoutMetricsValue = lastLayoutMetrics_.load(); + // compare_exchange_strong atomically swap the values if they're different, or + // return false if the values are the same. + if (!lastLayoutMetrics_.compare_exchange_strong( + lastLayoutMetricsValue, layoutMetrics)) { + return; + } + dispatchEvent("layout", [frame = layoutMetrics.frame](jsi::Runtime &runtime) { auto layout = jsi::Object(runtime); layout.setProperty(runtime, "x", frame.origin.x); diff --git a/ReactCommon/fabric/components/view/ViewEventEmitter.h b/ReactCommon/fabric/components/view/ViewEventEmitter.h index cac9593baa874f..0920931a12f8a0 100644 --- a/ReactCommon/fabric/components/view/ViewEventEmitter.h +++ b/ReactCommon/fabric/components/view/ViewEventEmitter.h @@ -7,6 +7,7 @@ #pragma once +#include #include #include @@ -35,6 +36,9 @@ class ViewEventEmitter : public TouchEventEmitter { #pragma mark - Layout void onLayout(const LayoutMetrics &layoutMetrics) const; + + private: + mutable std::atomic lastLayoutMetrics_; }; } // namespace react