diff --git a/packages/react-native/ReactCommon/react/renderer/core/EventEmitter.cpp b/packages/react-native/ReactCommon/react/renderer/core/EventEmitter.cpp index b2e5bf04b54..b4af39c6841 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/EventEmitter.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/EventEmitter.cpp @@ -94,6 +94,16 @@ void EventEmitter::dispatchEvent( return; } + // Allows the event listener to interrupt default event dispatch + if (payload != nullptr) { + if (eventListeners_.willDispatchEvent( + eventTarget_ != nullptr ? eventTarget_->getTag() : 0, + type, + *payload)) { + return; + } + } + eventDispatcher->dispatchEvent(RawEvent( normalizeEventType(std::move(type)), std::move(payload), @@ -119,6 +129,16 @@ void EventEmitter::dispatchUniqueEvent( return; } + // Allows the event listener to interrupt default event dispatch + if (payload != nullptr) { + if (eventListeners_.willDispatchEvent( + eventTarget_ != nullptr ? eventTarget_->getTag() : 0, + type, + *payload)) { + return; + } + } + eventDispatcher->dispatchUniqueEvent(RawEvent( normalizeEventType(std::move(type)), std::move(payload), @@ -153,4 +173,17 @@ const SharedEventTarget& EventEmitter::getEventTarget() const { return eventTarget_; } +void EventEmitter::addListener( + std::shared_ptr listener) const { + eventListeners_.addListener(std::move(listener)); +} + +/* + * Removes provided event listener to the event dispatcher. + */ +void EventEmitter::removeListener( + const std::shared_ptr& listener) const { + eventListeners_.removeListener(listener); +} + } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/core/EventEmitter.h b/packages/react-native/ReactCommon/react/renderer/core/EventEmitter.h index 7651b4ccec4..d2b4237526c 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/EventEmitter.h +++ b/packages/react-native/ReactCommon/react/renderer/core/EventEmitter.h @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -103,12 +104,25 @@ class EventEmitter { void dispatchUniqueEvent(std::string type, SharedEventPayload payload) const; +#pragma mark - Event listeners + /* + * Adds provided event listener to the event dispatcher. + */ + void addListener(std::shared_ptr listener) const; + + /* + * Removes provided event listener to the event dispatcher. + */ + void removeListener( + const std::shared_ptr& listener) const; + private: friend class UIManagerBinding; mutable SharedEventTarget eventTarget_; EventDispatcher::Weak eventDispatcher_; + mutable EventEmitterListenerContainer eventListeners_{}; mutable int enableCounter_{0}; mutable bool isEnabled_{false}; }; diff --git a/packages/react-native/ReactCommon/react/renderer/core/EventListener.cpp b/packages/react-native/ReactCommon/react/renderer/core/EventListener.cpp deleted file mode 100644 index a64e24fdff7..00000000000 --- a/packages/react-native/ReactCommon/react/renderer/core/EventListener.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "EventListener.h" - -#include - -namespace facebook::react { - -bool EventListenerContainer::willDispatchEvent(const RawEvent& event) { - std::shared_lock lock(mutex_); - - bool handled = false; - for (const auto& listener : eventListeners_) { - handled = (*listener)(event); - if (handled) { - break; - } - } - return handled; -} - -void EventListenerContainer::addListener( - std::shared_ptr listener) { - std::unique_lock lock(mutex_); - - eventListeners_.push_back(std::move(listener)); -} - -void EventListenerContainer::removeListener( - const std::shared_ptr& listener) { - std::unique_lock lock(mutex_); - - auto it = std::find(eventListeners_.begin(), eventListeners_.end(), listener); - if (it != eventListeners_.end()) { - eventListeners_.erase(it); - } -} - -} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/core/EventListener.h b/packages/react-native/ReactCommon/react/renderer/core/EventListener.h index 1d5e72168dd..8f15ebcd92b 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/EventListener.h +++ b/packages/react-native/ReactCommon/react/renderer/core/EventListener.h @@ -7,9 +7,10 @@ #pragma once +#include #include -#include +#include #include namespace facebook::react { @@ -19,23 +20,55 @@ namespace facebook::react { * Return `true` to interrupt default dispatch to JS event emitter, `false` to * pass through to default handlers. */ -using EventListener = std::function; -class EventListenerContainer { +template +using EventListenerT = std::function; + +template +class EventListenerContainerT { public: /* * Invoke listeners in this container with the event. * Returns true if event was handled by the listener, false to continue * default dispatch. */ - bool willDispatchEvent(const RawEvent& event); + bool willDispatchEvent(TArgs... args) { + std::shared_lock lock(mutex_); + bool handled = false; + for (const auto& listener : eventListeners_) { + handled = (*listener)(args...); + if (handled) { + break; + } + } + return handled; + } - void addListener(std::shared_ptr listener); - void removeListener(const std::shared_ptr& listener); + void addListener(std::shared_ptr> listener) { + std::unique_lock lock(mutex_); + eventListeners_.push_back(std::move(listener)); + } + + void removeListener( + const std::shared_ptr>& listener) { + std::unique_lock lock(mutex_); + auto it = + std::find(eventListeners_.begin(), eventListeners_.end(), listener); + if (it != eventListeners_.end()) { + eventListeners_.erase(it); + } + } private: std::shared_mutex mutex_; - std::vector> eventListeners_; + std::vector>> eventListeners_; }; +using EventListener = EventListenerT; +using EventListenerContainer = EventListenerContainerT; +using EventEmitterListener = + EventListenerT; +using EventEmitterListenerContainer = + EventListenerContainerT; + } // namespace facebook::react