mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Allow listeners in EventEmitter (#49998)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/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
This commit is contained in:
committed by
Facebook GitHub Bot
parent
9d7cdfef17
commit
ff4537c15e
@@ -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<const EventEmitterListener> listener) const {
|
||||
eventListeners_.addListener(std::move(listener));
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes provided event listener to the event dispatcher.
|
||||
*/
|
||||
void EventEmitter::removeListener(
|
||||
const std::shared_ptr<const EventEmitterListener>& listener) const {
|
||||
eventListeners_.removeListener(listener);
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <folly/dynamic.h>
|
||||
#include <react/renderer/core/EventDispatcher.h>
|
||||
#include <react/renderer/core/EventListener.h>
|
||||
#include <react/renderer/core/EventPayload.h>
|
||||
#include <react/renderer/core/EventTarget.h>
|
||||
#include <react/renderer/core/ReactPrimitives.h>
|
||||
@@ -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<const EventEmitterListener> listener) const;
|
||||
|
||||
/*
|
||||
* Removes provided event listener to the event dispatcher.
|
||||
*/
|
||||
void removeListener(
|
||||
const std::shared_ptr<const EventEmitterListener>& listener) const;
|
||||
|
||||
private:
|
||||
friend class UIManagerBinding;
|
||||
|
||||
mutable SharedEventTarget eventTarget_;
|
||||
|
||||
EventDispatcher::Weak eventDispatcher_;
|
||||
mutable EventEmitterListenerContainer eventListeners_{};
|
||||
mutable int enableCounter_{0};
|
||||
mutable bool isEnabled_{false};
|
||||
};
|
||||
|
||||
@@ -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 <mutex>
|
||||
|
||||
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<const EventListener> listener) {
|
||||
std::unique_lock lock(mutex_);
|
||||
|
||||
eventListeners_.push_back(std::move(listener));
|
||||
}
|
||||
|
||||
void EventListenerContainer::removeListener(
|
||||
const std::shared_ptr<const EventListener>& 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
|
||||
@@ -7,9 +7,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
|
||||
#include <react/renderer/core/EventPayload.h>
|
||||
#include <react/renderer/core/RawEvent.h>
|
||||
|
||||
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<bool(const RawEvent& event)>;
|
||||
|
||||
class EventListenerContainer {
|
||||
template <typename... TArgs>
|
||||
using EventListenerT = std::function<bool(TArgs...)>;
|
||||
|
||||
template <typename... TArgs>
|
||||
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<const EventListener> listener);
|
||||
void removeListener(const std::shared_ptr<const EventListener>& listener);
|
||||
void addListener(std::shared_ptr<const EventListenerT<TArgs...>> listener) {
|
||||
std::unique_lock lock(mutex_);
|
||||
eventListeners_.push_back(std::move(listener));
|
||||
}
|
||||
|
||||
void removeListener(
|
||||
const std::shared_ptr<const EventListenerT<TArgs...>>& 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<std::shared_ptr<const EventListener>> eventListeners_;
|
||||
std::vector<std::shared_ptr<const EventListenerT<TArgs...>>> eventListeners_;
|
||||
};
|
||||
|
||||
using EventListener = EventListenerT<const RawEvent&>;
|
||||
using EventListenerContainer = EventListenerContainerT<const RawEvent&>;
|
||||
using EventEmitterListener =
|
||||
EventListenerT<Tag, const std::string&, const EventPayload&>;
|
||||
using EventEmitterListenerContainer =
|
||||
EventListenerContainerT<Tag, const std::string&, const EventPayload&>;
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
Reference in New Issue
Block a user