88 */
99
1010import { registrationNameDependencies } from 'events/EventPluginRegistry' ;
11+ import type { DOMTopLevelEventType } from 'events/TopLevelEventTypes' ;
1112import {
1213 TOP_BLUR ,
1314 TOP_CANCEL ,
@@ -84,22 +85,23 @@ import isEventSupported from './isEventSupported';
8485 * React Core . General Purpose Event Plugin System
8586 */
8687
87- const alreadyListeningTo = { } ;
88- let reactTopListenersCounter = 0 ;
88+ const PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map ;
89+ const elementListeningSets :
90+ | WeakMap
91+ | Map <
92+ Document | Element | Node ,
93+ Set < DOMTopLevelEventType > ,
94+ > = new PossiblyWeakMap ( ) ;
8995
90- /**
91- * To ensure no conflicts with other potential React instances on the page
92- */
93- const topListenersIDKey = '_reactListenersID' + ( '' + Math . random ( ) ) . slice ( 2 ) ;
94-
95- function getListeningForDocument ( mountAt : any ) {
96- // In IE8, `mountAt` is a host object and doesn't have `hasOwnProperty`
97- // directly.
98- if ( ! Object . prototype . hasOwnProperty . call ( mountAt , topListenersIDKey ) ) {
99- mountAt [ topListenersIDKey ] = reactTopListenersCounter ++ ;
100- alreadyListeningTo [ mountAt [ topListenersIDKey ] ] = { } ;
96+ function getListeningSetForElement (
97+ element : Document | Element | Node ,
98+ ) : Set < DOMTopLevelEventType > {
99+ let listeningSet = elementListeningSets . get ( element ) ;
100+ if ( listeningSet === undefined ) {
101+ listeningSet = new Set ( ) ;
102+ elementListeningSets . set ( element , listeningSet ) ;
101103 }
102- return alreadyListeningTo [ mountAt [ topListenersIDKey ] ] ;
104+ return listeningSet ;
103105}
104106
105107/**
@@ -125,14 +127,14 @@ function getListeningForDocument(mountAt: any) {
125127 */
126128export function listenTo (
127129 registrationName : string ,
128- mountAt : Document | Element ,
129- ) {
130- const isListening = getListeningForDocument ( mountAt ) ;
130+ mountAt : Document | Element | Node ,
131+ ) : void {
132+ const listeningSet = getListeningSetForElement ( mountAt ) ;
131133 const dependencies = registrationNameDependencies [ registrationName ] ;
132134
133135 for ( let i = 0 ; i < dependencies . length ; i ++ ) {
134136 const dependency = dependencies [ i ] ;
135- if ( ! ( isListening . hasOwnProperty ( dependency ) && isListening [ dependency ] ) ) {
137+ if ( ! listeningSet . has ( dependency ) ) {
136138 switch ( dependency ) {
137139 case TOP_SCROLL :
138140 trapCapturedEvent ( TOP_SCROLL , mountAt ) ;
@@ -143,8 +145,8 @@ export function listenTo(
143145 trapCapturedEvent ( TOP_BLUR , mountAt ) ;
144146 // We set the flag for a single dependency later in this function,
145147 // but this ensures we mark both as attached rather than just one.
146- isListening [ TOP_BLUR ] = true ;
147- isListening [ TOP_FOCUS ] = true ;
148+ listeningSet . add ( TOP_BLUR ) ;
149+ listeningSet . add ( TOP_FOCUS ) ;
148150 break ;
149151 case TOP_CANCEL :
150152 case TOP_CLOSE :
@@ -167,20 +169,21 @@ export function listenTo(
167169 }
168170 break ;
169171 }
170- isListening [ dependency ] = true ;
172+ listeningSet . add ( dependency ) ;
171173 }
172174 }
173175}
174176
175177export function isListeningToAllDependencies (
176178 registrationName : string ,
177179 mountAt : Document | Element ,
178- ) {
179- const isListening = getListeningForDocument ( mountAt ) ;
180+ ) : boolean {
181+ const listeningSet = getListeningSetForElement ( mountAt ) ;
180182 const dependencies = registrationNameDependencies [ registrationName ] ;
183+
181184 for ( let i = 0 ; i < dependencies . length ; i ++ ) {
182185 const dependency = dependencies [ i ] ;
183- if ( ! ( isListening . hasOwnProperty ( dependency ) && isListening [ dependency ] ) ) {
186+ if ( ! listeningSet . has ( dependency ) ) {
184187 return false ;
185188 }
186189 }
0 commit comments