@samitouri / QOS-React / commits / 9d4e8e84f7

React Native raw event EventEmitter - intended for app-specific perf listeners and debugging (#23232)

* RawEventEmitter: new event perf profiling mechanism outside of Pressability to capture all touch events, and other event types * sync * concise notation * Move event telemetry event emitter call from Plugin to ReactFabricEventEmitter, to reduce reliance on the plugin system and move the emit call further into the core * Backout changes to ReactNativeEventPluginOrder * Properly flow typing event emitter, and emit event to two channels: named and catchall * fix typing for event name string * fix typing for event name string * fix flow * Add more comments about how the event telemetry system works * Add more comments about how the event telemetry system works * rename to RawEventTelemetryEventEmitterOffByDefault * yarn prettier-all * rename event * comments * improve flow types * renamed file

Joshua Gross committed Feb 7, 2022 at 18:34 UTC 9d4e8e84f7fb782385d81ffcdcda73822acf4ad1
4 files changed +58 -1
packages/react-native-renderer/src/ReactFabricEventEmitter.js
+28 -1
@@ -21,6 +21,8 @@ import {plugins} from './legacy-events/EventPluginRegistry';
21 import getListener from './ReactNativeGetListener';
22 import {runEventsInBatch} from './legacy-events/EventBatching';
23
24 +import {RawEventEmitter} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
25 +
26 export {getListener, registrationNameModules as registrationNames};
27
28 /**
@@ -73,7 +75,7 @@ function runExtractedPluginEventsInBatch(
75
76 export function dispatchEvent(
77 target: null | Object,
76 - topLevelType: TopLevelType,
78 + topLevelType: RNTopLevelEventType,
79 nativeEvent: AnyNativeEvent,
80 ) {
81 const targetFiber = (target: null | Fiber);
@@ -88,6 +90,31 @@ export function dispatchEvent(
90 }
91
92 batchedUpdates(function() {
93 + // Emit event to the RawEventEmitter. This is an unused-by-default EventEmitter
94 + // that can be used to instrument event performance monitoring (primarily - could be useful
95 + // for other things too).
96 + //
97 + // NOTE: this merely emits events into the EventEmitter below.
98 + // If *you* do not add listeners to the `RawEventEmitter`,
99 + // then all of these emitted events will just blackhole and are no-ops.
100 + // It is available (although not officially supported... yet) if you want to collect
101 + // perf data on event latency in your application, and could also be useful for debugging
102 + // low-level events issues.
103 + //
104 + // If you do not have any event perf monitoring and are extremely concerned about event perf,
105 + // it is safe to disable these "emit" statements; it will prevent checking the size of
106 + // an empty array twice and prevent two no-ops. Practically the overhead is so low that
107 + // we don't think it's worth thinking about in prod; your perf issues probably lie elsewhere.
108 + //
109 + // We emit two events here: one for listeners to this specific event,
110 + // and one for the catchall listener '*', for any listeners that want
111 + // to be notified for all events.
112 + // Note that extracted events are *not* emitted,
113 + // only events that have a 1:1 mapping with a native event, at least for now.
114 + const event = {eventName: topLevelType, nativeEvent};
115 + RawEventEmitter.emit(topLevelType, event);
116 + RawEventEmitter.emit('*', event);
117 +
118 // Heritage plugin event system
119 runExtractedPluginEventsInBatch(
120 topLevelType,
packages/react-native-renderer/src/__mocks__/react-native/Libraries/ReactPrivate/RawEventEmitter.js new
+16
@@ -0,0 +1,16 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +
8 +'use strict';
9 +
10 +// See the react-native repository for a full implementation.
11 +// However, this is just an EventEmitter.
12 +const RawEventEmitter = {
13 + emit: jest.fn(),
14 +};
15 +
16 +module.exports = {default: RawEventEmitter};
packages/react-native-renderer/src/__mocks__/react-native/Libraries/ReactPrivate/ReactNativePrivateInterface.js
+3
@@ -41,4 +41,7 @@ module.exports = {
41 get legacySendAccessibilityEvent() {
42 return require('./legacySendAccessibilityEvent');
43 },
44 + get RawEventEmitter() {
45 + return require('./RawEventEmitter').default;
46 + },
47 };
scripts/flow/react-native-host-hooks.js
+11
@@ -21,6 +21,13 @@ import type {CapturedError} from 'react-reconciler/src/ReactCapturedValue';
21 import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
22
23 type DeepDifferOptions = {|+unsafelyIgnoreFunctions?: boolean|};
24 +type RawEventEmitterEvent = $ReadOnly<{|
25 + eventName: string,
26 + // We expect, but do not/cannot require, that nativeEvent is an object
27 + // with the properties: key, elementType (string), type (string), tag (numeric),
28 + // and a stateNode of the native element/Fiber the event was emitted to.
29 + nativeEvent: {[string]: mixed},
30 +|}>;
31
32 declare module 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface' {
33 declare export function deepDiffer(
@@ -127,6 +134,10 @@ declare module 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'
134 get: (name: string) => ReactNativeBaseComponentViewConfig,
135 ...
136 };
137 + declare export var RawEventEmitter: {
138 + emit: (channel: string, event: RawEventEmitterEvent) => string,
139 + ...
140 + };
141 }
142
143 declare module 'react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore' {