Files
react-native/ReactCommon/fabric/core/events/EventEmitter.cpp
T
Samuel Susla b31149cf90 Introduce BatchedEventQueue::enqueueUniqueEvent
Summary:
Changelog: [Internal]

`BatchedEventQueue::enqueueUniqueEvent` goes over event queue and deletes previous event of the same type and same target.

This is useful for ScrollView for example where only the latest event is relevant.
This only affects ScrollView scroll event, other events take the original code path.

Reviewed By: mdvacca

Differential Revision: D21648906

fbshipit-source-id: a80ad652058fd50ebb55e24a87229cdc1764b591
2020-05-21 11:56:22 -07:00

119 lines
3.1 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "EventEmitter.h"
#include <folly/dynamic.h>
#include <jsi/JSIDynamic.h>
#include <jsi/jsi.h>
#include <react/debug/SystraceSection.h>
#include "RawEvent.h"
namespace facebook {
namespace react {
// TODO(T29874519): Get rid of "top" prefix once and for all.
/*
* Capitalizes the first letter of the event type and adds "top" prefix if
* necessary (e.g. "layout" becames "topLayout").
*/
static std::string normalizeEventType(const std::string &type) {
auto prefixedType = type;
if (type.find("top", 0) != 0) {
prefixedType.insert(0, "top");
prefixedType[3] = toupper(prefixedType[3]);
}
return prefixedType;
}
std::mutex &EventEmitter::DispatchMutex() {
static std::mutex mutex;
return mutex;
}
ValueFactory EventEmitter::defaultPayloadFactory() {
static auto payloadFactory =
ValueFactory{[](jsi::Runtime &runtime) { return jsi::Object(runtime); }};
return payloadFactory;
}
EventEmitter::EventEmitter(
SharedEventTarget eventTarget,
Tag tag,
EventDispatcher::Weak eventDispatcher)
: eventTarget_(std::move(eventTarget)),
eventDispatcher_(std::move(eventDispatcher)) {}
void EventEmitter::dispatchEvent(
const std::string &type,
const folly::dynamic &payload,
const EventPriority &priority) const {
dispatchEvent(
type,
[payload](jsi::Runtime &runtime) {
return valueFromDynamic(runtime, payload);
},
priority);
}
void EventEmitter::dispatchEvent(
const std::string &type,
const ValueFactory &payloadFactory,
const EventPriority &priority) const {
SystraceSection s("EventEmitter::dispatchEvent");
auto eventDispatcher = eventDispatcher_.lock();
if (!eventDispatcher) {
return;
}
eventDispatcher->dispatchEvent(
RawEvent(normalizeEventType(type), payloadFactory, eventTarget_),
priority);
}
void EventEmitter::dispatchUniqueEvent(
const std::string &type,
const ValueFactory &payloadFactory) const {
SystraceSection s("EventEmitter::dispatchUniqueEvent");
auto eventDispatcher = eventDispatcher_.lock();
if (!eventDispatcher) {
return;
}
eventDispatcher->dispatchUniqueEvent(
RawEvent(normalizeEventType(type), payloadFactory, eventTarget_));
}
void EventEmitter::setEnabled(bool enabled) const {
enableCounter_ += enabled ? 1 : -1;
bool shouldBeEnabled = enableCounter_ > 0;
if (isEnabled_ != shouldBeEnabled) {
isEnabled_ = shouldBeEnabled;
if (eventTarget_) {
eventTarget_->setEnabled(isEnabled_);
}
}
// Note: Initially, the state of `eventTarget_` and the value `enableCounter_`
// is mismatched intentionally (it's `non-null` and `0` accordingly). We need
// this to support an initial nebula state where the event target must be
// retained without any associated mounted node.
bool shouldBeRetained = enableCounter_ > 0;
if (shouldBeRetained != (eventTarget_ != nullptr)) {
if (!shouldBeRetained) {
eventTarget_.reset();
}
}
}
} // namespace react
} // namespace facebook