Skip to content

Commit ff4537c

Browse files
rozelefacebook-github-bot
authored andcommitted
Allow listeners in EventEmitter (facebook#49998)
Summary: Pull Request resolved: facebook#49998 We have listeners for EventDispatcher, but we don't have any listener capabilities for synchronous hooks from events on the UI thread. This proposal adds an affordance for generic event listeners that can be attached by the host platform mounting manager, e.g., to wire events to NativeAnimated event drivers. ## Changelog [General][Added] - EventEmitter `addListener` and `removeListener` APIs Reviewed By: javache Differential Revision: D71050838 fbshipit-source-id: a7f298c71bd882a573781c2fe1fb5a1ae79f301c
1 parent 9d7cdfe commit ff4537c

File tree

4 files changed

+87
-51
lines changed

4 files changed

+87
-51
lines changed

packages/react-native/ReactCommon/react/renderer/core/EventEmitter.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,16 @@ void EventEmitter::dispatchEvent(
9494
return;
9595
}
9696

97+
// Allows the event listener to interrupt default event dispatch
98+
if (payload != nullptr) {
99+
if (eventListeners_.willDispatchEvent(
100+
eventTarget_ != nullptr ? eventTarget_->getTag() : 0,
101+
type,
102+
*payload)) {
103+
return;
104+
}
105+
}
106+
97107
eventDispatcher->dispatchEvent(RawEvent(
98108
normalizeEventType(std::move(type)),
99109
std::move(payload),
@@ -119,6 +129,16 @@ void EventEmitter::dispatchUniqueEvent(
119129
return;
120130
}
121131

132+
// Allows the event listener to interrupt default event dispatch
133+
if (payload != nullptr) {
134+
if (eventListeners_.willDispatchEvent(
135+
eventTarget_ != nullptr ? eventTarget_->getTag() : 0,
136+
type,
137+
*payload)) {
138+
return;
139+
}
140+
}
141+
122142
eventDispatcher->dispatchUniqueEvent(RawEvent(
123143
normalizeEventType(std::move(type)),
124144
std::move(payload),
@@ -153,4 +173,17 @@ const SharedEventTarget& EventEmitter::getEventTarget() const {
153173
return eventTarget_;
154174
}
155175

176+
void EventEmitter::addListener(
177+
std::shared_ptr<const EventEmitterListener> listener) const {
178+
eventListeners_.addListener(std::move(listener));
179+
}
180+
181+
/*
182+
* Removes provided event listener to the event dispatcher.
183+
*/
184+
void EventEmitter::removeListener(
185+
const std::shared_ptr<const EventEmitterListener>& listener) const {
186+
eventListeners_.removeListener(listener);
187+
}
188+
156189
} // namespace facebook::react

packages/react-native/ReactCommon/react/renderer/core/EventEmitter.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <folly/dynamic.h>
1414
#include <react/renderer/core/EventDispatcher.h>
15+
#include <react/renderer/core/EventListener.h>
1516
#include <react/renderer/core/EventPayload.h>
1617
#include <react/renderer/core/EventTarget.h>
1718
#include <react/renderer/core/ReactPrimitives.h>
@@ -103,12 +104,25 @@ class EventEmitter {
103104

104105
void dispatchUniqueEvent(std::string type, SharedEventPayload payload) const;
105106

107+
#pragma mark - Event listeners
108+
/*
109+
* Adds provided event listener to the event dispatcher.
110+
*/
111+
void addListener(std::shared_ptr<const EventEmitterListener> listener) const;
112+
113+
/*
114+
* Removes provided event listener to the event dispatcher.
115+
*/
116+
void removeListener(
117+
const std::shared_ptr<const EventEmitterListener>& listener) const;
118+
106119
private:
107120
friend class UIManagerBinding;
108121

109122
mutable SharedEventTarget eventTarget_;
110123

111124
EventDispatcher::Weak eventDispatcher_;
125+
mutable EventEmitterListenerContainer eventListeners_{};
112126
mutable int enableCounter_{0};
113127
mutable bool isEnabled_{false};
114128
};

packages/react-native/ReactCommon/react/renderer/core/EventListener.cpp

Lines changed: 0 additions & 44 deletions
This file was deleted.

packages/react-native/ReactCommon/react/renderer/core/EventListener.h

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77

88
#pragma once
99

10+
#include <mutex>
1011
#include <shared_mutex>
11-
#include <string>
1212

13+
#include <react/renderer/core/EventPayload.h>
1314
#include <react/renderer/core/RawEvent.h>
1415

1516
namespace facebook::react {
@@ -19,23 +20,55 @@ namespace facebook::react {
1920
* Return `true` to interrupt default dispatch to JS event emitter, `false` to
2021
* pass through to default handlers.
2122
*/
22-
using EventListener = std::function<bool(const RawEvent& event)>;
2323

24-
class EventListenerContainer {
24+
template <typename... TArgs>
25+
using EventListenerT = std::function<bool(TArgs...)>;
26+
27+
template <typename... TArgs>
28+
class EventListenerContainerT {
2529
public:
2630
/*
2731
* Invoke listeners in this container with the event.
2832
* Returns true if event was handled by the listener, false to continue
2933
* default dispatch.
3034
*/
31-
bool willDispatchEvent(const RawEvent& event);
35+
bool willDispatchEvent(TArgs... args) {
36+
std::shared_lock lock(mutex_);
37+
bool handled = false;
38+
for (const auto& listener : eventListeners_) {
39+
handled = (*listener)(args...);
40+
if (handled) {
41+
break;
42+
}
43+
}
44+
return handled;
45+
}
46+
47+
void addListener(std::shared_ptr<const EventListenerT<TArgs...>> listener) {
48+
std::unique_lock lock(mutex_);
49+
eventListeners_.push_back(std::move(listener));
50+
}
3251

33-
void addListener(std::shared_ptr<const EventListener> listener);
34-
void removeListener(const std::shared_ptr<const EventListener>& listener);
52+
void removeListener(
53+
const std::shared_ptr<const EventListenerT<TArgs...>>& listener) {
54+
std::unique_lock lock(mutex_);
55+
auto it =
56+
std::find(eventListeners_.begin(), eventListeners_.end(), listener);
57+
if (it != eventListeners_.end()) {
58+
eventListeners_.erase(it);
59+
}
60+
}
3561

3662
private:
3763
std::shared_mutex mutex_;
38-
std::vector<std::shared_ptr<const EventListener>> eventListeners_;
64+
std::vector<std::shared_ptr<const EventListenerT<TArgs...>>> eventListeners_;
3965
};
4066

67+
using EventListener = EventListenerT<const RawEvent&>;
68+
using EventListenerContainer = EventListenerContainerT<const RawEvent&>;
69+
using EventEmitterListener =
70+
EventListenerT<Tag, const std::string&, const EventPayload&>;
71+
using EventEmitterListenerContainer =
72+
EventListenerContainerT<Tag, const std::string&, const EventPayload&>;
73+
4174
} // namespace facebook::react

0 commit comments

Comments
 (0)