@samitouri / QOS-React-2 / commits / 4a3f779d67

Remove event pooling in the modern system (#18969)

Dominic Gannaway committed May 21, 2020 at 13:54 UTC 4a3f779d67d7d7f69cb2340c788826b86b34ce05
7 files changed +412 -361
packages/legacy-events/SyntheticEvent.js
+92 -71
@@ -157,7 +157,10 @@ Object.assign(SyntheticEvent.prototype, {
157 * won't be added back into the pool.
158 */
159 persist: function() {
160 - this.isPersistent = functionThatReturnsTrue;
160 + // Modern event system doesn't use pooling.
161 + if (!enableModernEventSystem) {
162 + this.isPersistent = functionThatReturnsTrue;
163 + }
164 },
165
166 /**
@@ -165,65 +168,68 @@ Object.assign(SyntheticEvent.prototype, {
168 *
169 * @return {boolean} True if this should not be released, false otherwise.
170 */
168 - isPersistent: functionThatReturnsFalse,
171 + isPersistent: enableModernEventSystem
172 + ? functionThatReturnsTrue
173 + : functionThatReturnsFalse,
174
175 /**
176 * `PooledClass` looks for `destructor` on each instance it releases.
177 */
178 destructor: function() {
174 - const Interface = this.constructor.Interface;
175 - for (const propName in Interface) {
179 + // Modern event system doesn't use pooling.
180 + if (!enableModernEventSystem) {
181 + const Interface = this.constructor.Interface;
182 + for (const propName in Interface) {
183 + if (__DEV__) {
184 + Object.defineProperty(
185 + this,
186 + propName,
187 + getPooledWarningPropertyDefinition(propName, Interface[propName]),
188 + );
189 + } else {
190 + this[propName] = null;
191 + }
192 + }
193 + this.dispatchConfig = null;
194 + this._targetInst = null;
195 + this.nativeEvent = null;
196 + this.isDefaultPrevented = functionThatReturnsFalse;
197 + this.isPropagationStopped = functionThatReturnsFalse;
198 + this._dispatchListeners = null;
199 + this._dispatchInstances = null;
200 if (__DEV__) {
201 Object.defineProperty(
202 this,
179 - propName,
180 - getPooledWarningPropertyDefinition(propName, Interface[propName]),
203 + 'nativeEvent',
204 + getPooledWarningPropertyDefinition('nativeEvent', null),
205 );
182 - } else {
183 - this[propName] = null;
184 - }
185 - }
186 - this.dispatchConfig = null;
187 - this._targetInst = null;
188 - this.nativeEvent = null;
189 - this.isDefaultPrevented = functionThatReturnsFalse;
190 - this.isPropagationStopped = functionThatReturnsFalse;
191 - if (!enableModernEventSystem) {
192 - this._dispatchListeners = null;
193 - this._dispatchInstances = null;
194 - }
195 - if (__DEV__) {
196 - Object.defineProperty(
197 - this,
198 - 'nativeEvent',
199 - getPooledWarningPropertyDefinition('nativeEvent', null),
200 - );
201 - Object.defineProperty(
202 - this,
203 - 'isDefaultPrevented',
204 - getPooledWarningPropertyDefinition(
206 + Object.defineProperty(
207 + this,
208 'isDefaultPrevented',
206 - functionThatReturnsFalse,
207 - ),
208 - );
209 - Object.defineProperty(
210 - this,
211 - 'isPropagationStopped',
212 - getPooledWarningPropertyDefinition(
209 + getPooledWarningPropertyDefinition(
210 + 'isDefaultPrevented',
211 + functionThatReturnsFalse,
212 + ),
213 + );
214 + Object.defineProperty(
215 + this,
216 'isPropagationStopped',
214 - functionThatReturnsFalse,
215 - ),
216 - );
217 - Object.defineProperty(
218 - this,
219 - 'preventDefault',
220 - getPooledWarningPropertyDefinition('preventDefault', () => {}),
221 - );
222 - Object.defineProperty(
223 - this,
224 - 'stopPropagation',
225 - getPooledWarningPropertyDefinition('stopPropagation', () => {}),
226 - );
217 + getPooledWarningPropertyDefinition(
218 + 'isPropagationStopped',
219 + functionThatReturnsFalse,
220 + ),
221 + );
222 + Object.defineProperty(
223 + this,
224 + 'preventDefault',
225 + getPooledWarningPropertyDefinition('preventDefault', () => {}),
226 + );
227 + Object.defineProperty(
228 + this,
229 + 'stopPropagation',
230 + getPooledWarningPropertyDefinition('stopPropagation', () => {}),
231 + );
232 + }
233 }
234 },
235 });
@@ -303,18 +309,26 @@ function getPooledWarningPropertyDefinition(propName, getVal) {
309 }
310 }
311
306 -function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) {
312 +function createOrGetPooledEvent(
313 + dispatchConfig,
314 + targetInst,
315 + nativeEvent,
316 + nativeInst,
317 +) {
318 const EventConstructor = this;
308 - if (EventConstructor.eventPool.length) {
309 - const instance = EventConstructor.eventPool.pop();
310 - EventConstructor.call(
311 - instance,
312 - dispatchConfig,
313 - targetInst,
314 - nativeEvent,
315 - nativeInst,
316 - );
317 - return instance;
319 + // Modern event system doesn't use pooling.
320 + if (!enableModernEventSystem) {
321 + if (EventConstructor.eventPool.length) {
322 + const instance = EventConstructor.eventPool.pop();
323 + EventConstructor.call(
324 + instance,
325 + dispatchConfig,
326 + targetInst,
327 + nativeEvent,
328 + nativeInst,
329 + );
330 + return instance;
331 + }
332 }
333 return new EventConstructor(
334 dispatchConfig,
@@ -325,21 +339,28 @@ function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) {
339 }
340
341 function releasePooledEvent(event) {
328 - const EventConstructor = this;
329 - invariant(
330 - event instanceof EventConstructor,
331 - 'Trying to release an event instance into a pool of a different type.',
332 - );
333 - event.destructor();
334 - if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) {
335 - EventConstructor.eventPool.push(event);
342 + // Modern event system doesn't use pooling.
343 + if (!enableModernEventSystem) {
344 + const EventConstructor = this;
345 + invariant(
346 + event instanceof EventConstructor,
347 + 'Trying to release an event instance into a pool of a different type.',
348 + );
349 + event.destructor();
350 + if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) {
351 + EventConstructor.eventPool.push(event);
352 + }
353 }
354 }
355
356 function addEventPoolingTo(EventConstructor) {
340 - EventConstructor.eventPool = [];
341 - EventConstructor.getPooled = getPooledEvent;
342 - EventConstructor.release = releasePooledEvent;
357 + EventConstructor.getPooled = createOrGetPooledEvent;
358 +
359 + // Modern event system doesn't use pooling.
360 + if (!enableModernEventSystem) {
361 + EventConstructor.eventPool = [];
362 + EventConstructor.release = releasePooledEvent;
363 + }
364 }
365
366 export default SyntheticEvent;
packages/react-dom/src/events/DOMModernPluginEventSystem.js
+1 -4
@@ -207,10 +207,7 @@ export function dispatchEventsInBatch(dispatchQueue: DispatchQueue): void {
207 const dispatchQueueItem: DispatchQueueItem = dispatchQueue[i];
208 const {event, capture, bubble} = dispatchQueueItem;
209 executeDispatchesInOrder(event, capture, bubble);
210 - // Release the event from the pool if needed
211 - if (!event.isPersistent()) {
212 - event.constructor.release(event);
213 - }
210 + // Modern event system doesn't use pooling.
211 }
212 // This would be a good time to rethrow if any of the event handlers threw.
213 rethrowCaughtError();
packages/react-dom/src/events/__tests__/DOMModernPluginEventSystem-test.internal.js
+21
@@ -78,6 +78,27 @@ describe('DOMModernPluginEventSystem', () => {
78 endNativeEventListenerClearDown();
79 });
80
81 + it('does not pool events', () => {
82 + const buttonRef = React.createRef();
83 + const log = [];
84 + const onClick = jest.fn(e => log.push(e));
85 +
86 + function Test() {
87 + return <button ref={buttonRef} onClick={onClick} />;
88 + }
89 +
90 + ReactDOM.render(<Test />, container);
91 +
92 + let buttonElement = buttonRef.current;
93 + dispatchClickEvent(buttonElement);
94 + expect(onClick).toHaveBeenCalledTimes(1);
95 + dispatchClickEvent(buttonElement);
96 + expect(onClick).toHaveBeenCalledTimes(2);
97 + expect(log[0]).not.toBe(log[1]);
98 + expect(log[0].type).toBe('click');
99 + expect(log[1].type).toBe('click');
100 + });
101 +
102 it('handle propagation of click events', () => {
103 const buttonRef = React.createRef();
104 const divRef = React.createRef();
packages/react-dom/src/events/__tests__/SyntheticClipboardEvent-test.js
+39 -36
@@ -11,6 +11,7 @@
11
12 let React;
13 let ReactDOM;
14 +const ReactFeatureFlags = require('shared/ReactFeatureFlags');
15
16 describe('SyntheticClipboardEvent', () => {
17 let container;
@@ -117,41 +118,43 @@ describe('SyntheticClipboardEvent', () => {
118 expect(expectedCount).toBe(3);
119 });
120
120 - it('is able to `persist`', () => {
121 - const persistentEvents = [];
122 - const eventHandler = event => {
123 - expect(event.isPersistent()).toBe(false);
124 - event.persist();
125 - expect(event.isPersistent()).toBe(true);
126 - persistentEvents.push(event);
127 - };
128 -
129 - const div = ReactDOM.render(
130 - <div
131 - onCopy={eventHandler}
132 - onCut={eventHandler}
133 - onPaste={eventHandler}
134 - />,
135 - container,
136 - );
137 -
138 - let event;
139 - event = document.createEvent('Event');
140 - event.initEvent('copy', true, true);
141 - div.dispatchEvent(event);
142 -
143 - event = document.createEvent('Event');
144 - event.initEvent('cut', true, true);
145 - div.dispatchEvent(event);
146 -
147 - event = document.createEvent('Event');
148 - event.initEvent('paste', true, true);
149 - div.dispatchEvent(event);
150 -
151 - expect(persistentEvents.length).toBe(3);
152 - expect(persistentEvents[0].type).toBe('copy');
153 - expect(persistentEvents[1].type).toBe('cut');
154 - expect(persistentEvents[2].type).toBe('paste');
155 - });
121 + if (!ReactFeatureFlags.enableModernEventSystem) {
122 + it('is able to `persist`', () => {
123 + const persistentEvents = [];
124 + const eventHandler = event => {
125 + expect(event.isPersistent()).toBe(false);
126 + event.persist();
127 + expect(event.isPersistent()).toBe(true);
128 + persistentEvents.push(event);
129 + };
130 +
131 + const div = ReactDOM.render(
132 + <div
133 + onCopy={eventHandler}
134 + onCut={eventHandler}
135 + onPaste={eventHandler}
136 + />,
137 + container,
138 + );
139 +
140 + let event;
141 + event = document.createEvent('Event');
142 + event.initEvent('copy', true, true);
143 + div.dispatchEvent(event);
144 +
145 + event = document.createEvent('Event');
146 + event.initEvent('cut', true, true);
147 + div.dispatchEvent(event);
148 +
149 + event = document.createEvent('Event');
150 + event.initEvent('paste', true, true);
151 + div.dispatchEvent(event);
152 +
153 + expect(persistentEvents.length).toBe(3);
154 + expect(persistentEvents[0].type).toBe('copy');
155 + expect(persistentEvents[1].type).toBe('cut');
156 + expect(persistentEvents[2].type).toBe('paste');
157 + });
158 + }
159 });
160 });
packages/react-dom/src/events/__tests__/SyntheticEvent-test.js
+191 -188
@@ -11,6 +11,7 @@
11
12 let React;
13 let ReactDOM;
14 +const ReactFeatureFlags = require('shared/ReactFeatureFlags');
15
16 describe('SyntheticEvent', () => {
17 let container;
@@ -99,223 +100,225 @@ describe('SyntheticEvent', () => {
100 expect(expectedCount).toBe(1);
101 });
102
102 - it('should be able to `persist`', () => {
103 - let expectedCount = 0;
104 - let syntheticEvent;
105 -
106 - const eventHandler = e => {
107 - expect(e.isPersistent()).toBe(false);
108 - e.persist();
109 - syntheticEvent = e;
110 - expect(e.isPersistent()).toBe(true);
111 -
112 - expectedCount++;
113 - };
114 - const node = ReactDOM.render(<div onClick={eventHandler} />, container);
115 -
116 - const event = document.createEvent('Event');
117 - event.initEvent('click', true, true);
118 - node.dispatchEvent(event);
119 -
120 - expect(syntheticEvent.type).toBe('click');
121 - expect(syntheticEvent.bubbles).toBe(true);
122 - expect(syntheticEvent.cancelable).toBe(true);
123 - expect(expectedCount).toBe(1);
124 - });
103 + if (!ReactFeatureFlags.enableModernEventSystem) {
104 + it('should be able to `persist`', () => {
105 + let expectedCount = 0;
106 + let syntheticEvent;
107 +
108 + const eventHandler = e => {
109 + expect(e.isPersistent()).toBe(false);
110 + e.persist();
111 + syntheticEvent = e;
112 + expect(e.isPersistent()).toBe(true);
113 +
114 + expectedCount++;
115 + };
116 + const node = ReactDOM.render(<div onClick={eventHandler} />, container);
117 +
118 + const event = document.createEvent('Event');
119 + event.initEvent('click', true, true);
120 + node.dispatchEvent(event);
121 +
122 + expect(syntheticEvent.type).toBe('click');
123 + expect(syntheticEvent.bubbles).toBe(true);
124 + expect(syntheticEvent.cancelable).toBe(true);
125 + expect(expectedCount).toBe(1);
126 + });
127
126 - it('should be nullified and log warnings if the synthetic event has not been persisted', () => {
127 - let expectedCount = 0;
128 - let syntheticEvent;
128 + it('should be nullified and log warnings if the synthetic event has not been persisted', () => {
129 + let expectedCount = 0;
130 + let syntheticEvent;
131
130 - const eventHandler = e => {
131 - syntheticEvent = e;
132 + const eventHandler = e => {
133 + syntheticEvent = e;
134
133 - expectedCount++;
134 - };
135 - const node = ReactDOM.render(<div onClick={eventHandler} />, container);
135 + expectedCount++;
136 + };
137 + const node = ReactDOM.render(<div onClick={eventHandler} />, container);
138
137 - const event = document.createEvent('Event');
138 - event.initEvent('click', true, true);
139 - node.dispatchEvent(event);
139 + const event = document.createEvent('Event');
140 + event.initEvent('click', true, true);
141 + node.dispatchEvent(event);
142
141 - const getExpectedWarning = property =>
142 - 'Warning: This synthetic event is reused for performance reasons. If ' +
143 - `you're seeing this, you're accessing the property \`${property}\` on a ` +
144 - 'released/nullified synthetic event. This is set to null. If you must ' +
145 - 'keep the original synthetic event around, use event.persist(). ' +
146 - 'See https://fb.me/react-event-pooling for more information.';
147 -
148 - // once for each property accessed
149 - expect(() =>
150 - expect(syntheticEvent.type).toBe(null),
151 - ).toErrorDev(getExpectedWarning('type'), {withoutStack: true});
152 - expect(() =>
153 - expect(syntheticEvent.nativeEvent).toBe(null),
154 - ).toErrorDev(getExpectedWarning('nativeEvent'), {withoutStack: true});
155 - expect(() =>
156 - expect(syntheticEvent.target).toBe(null),
157 - ).toErrorDev(getExpectedWarning('target'), {withoutStack: true});
143 + const getExpectedWarning = property =>
144 + 'Warning: This synthetic event is reused for performance reasons. If ' +
145 + `you're seeing this, you're accessing the property \`${property}\` on a ` +
146 + 'released/nullified synthetic event. This is set to null. If you must ' +
147 + 'keep the original synthetic event around, use event.persist(). ' +
148 + 'See https://fb.me/react-event-pooling for more information.';
149 +
150 + // once for each property accessed
151 + expect(() =>
152 + expect(syntheticEvent.type).toBe(null),
153 + ).toErrorDev(getExpectedWarning('type'), {withoutStack: true});
154 + expect(() =>
155 + expect(syntheticEvent.nativeEvent).toBe(null),
156 + ).toErrorDev(getExpectedWarning('nativeEvent'), {withoutStack: true});
157 + expect(() =>
158 + expect(syntheticEvent.target).toBe(null),
159 + ).toErrorDev(getExpectedWarning('target'), {withoutStack: true});
160 +
161 + expect(expectedCount).toBe(1);
162 + });
163
159 - expect(expectedCount).toBe(1);
160 - });
164 + it('should warn when setting properties of a synthetic event that has not been persisted', () => {
165 + let expectedCount = 0;
166 + let syntheticEvent;
167
162 - it('should warn when setting properties of a synthetic event that has not been persisted', () => {
163 - let expectedCount = 0;
164 - let syntheticEvent;
168 + const eventHandler = e => {
169 + syntheticEvent = e;
170
166 - const eventHandler = e => {
167 - syntheticEvent = e;
171 + expectedCount++;
172 + };
173 + const node = ReactDOM.render(<div onClick={eventHandler} />, container);
174
169 - expectedCount++;
170 - };
171 - const node = ReactDOM.render(<div onClick={eventHandler} />, container);
175 + const event = document.createEvent('Event');
176 + event.initEvent('click', true, true);
177 + node.dispatchEvent(event);
178
173 - const event = document.createEvent('Event');
174 - event.initEvent('click', true, true);
175 - node.dispatchEvent(event);
179 + expect(() => {
180 + syntheticEvent.type = 'MouseEvent';
181 + }).toErrorDev(
182 + 'Warning: This synthetic event is reused for performance reasons. If ' +
183 + "you're seeing this, you're setting the property `type` on a " +
184 + 'released/nullified synthetic event. This is effectively a no-op. If you must ' +
185 + 'keep the original synthetic event around, use event.persist(). ' +
186 + 'See https://fb.me/react-event-pooling for more information.',
187 + {withoutStack: true},
188 + );
189 + expect(expectedCount).toBe(1);
190 + });
191
177 - expect(() => {
178 - syntheticEvent.type = 'MouseEvent';
179 - }).toErrorDev(
180 - 'Warning: This synthetic event is reused for performance reasons. If ' +
181 - "you're seeing this, you're setting the property `type` on a " +
182 - 'released/nullified synthetic event. This is effectively a no-op. If you must ' +
183 - 'keep the original synthetic event around, use event.persist(). ' +
184 - 'See https://fb.me/react-event-pooling for more information.',
185 - {withoutStack: true},
186 - );
187 - expect(expectedCount).toBe(1);
188 - });
192 + it('should warn when calling `preventDefault` if the synthetic event has not been persisted', () => {
193 + let expectedCount = 0;
194 + let syntheticEvent;
195
190 - it('should warn when calling `preventDefault` if the synthetic event has not been persisted', () => {
191 - let expectedCount = 0;
192 - let syntheticEvent;
196 + const eventHandler = e => {
197 + syntheticEvent = e;
198 + expectedCount++;
199 + };
200 + const node = ReactDOM.render(<div onClick={eventHandler} />, container);
201
194 - const eventHandler = e => {
195 - syntheticEvent = e;
196 - expectedCount++;
197 - };
198 - const node = ReactDOM.render(<div onClick={eventHandler} />, container);
202 + const event = document.createEvent('Event');
203 + event.initEvent('click', true, true);
204 + node.dispatchEvent(event);
205
200 - const event = document.createEvent('Event');
201 - event.initEvent('click', true, true);
202 - node.dispatchEvent(event);
206 + expect(() =>
207 + syntheticEvent.preventDefault(),
208 + ).toErrorDev(
209 + 'Warning: This synthetic event is reused for performance reasons. If ' +
210 + "you're seeing this, you're accessing the method `preventDefault` on a " +
211 + 'released/nullified synthetic event. This is a no-op function. If you must ' +
212 + 'keep the original synthetic event around, use event.persist(). ' +
213 + 'See https://fb.me/react-event-pooling for more information.',
214 + {withoutStack: true},
215 + );
216 + expect(expectedCount).toBe(1);
217 + });
218
204 - expect(() =>
205 - syntheticEvent.preventDefault(),
206 - ).toErrorDev(
207 - 'Warning: This synthetic event is reused for performance reasons. If ' +
208 - "you're seeing this, you're accessing the method `preventDefault` on a " +
209 - 'released/nullified synthetic event. This is a no-op function. If you must ' +
210 - 'keep the original synthetic event around, use event.persist(). ' +
211 - 'See https://fb.me/react-event-pooling for more information.',
212 - {withoutStack: true},
213 - );
214 - expect(expectedCount).toBe(1);
215 - });
219 + it('should warn when calling `stopPropagation` if the synthetic event has not been persisted', () => {
220 + let expectedCount = 0;
221 + let syntheticEvent;
222
217 - it('should warn when calling `stopPropagation` if the synthetic event has not been persisted', () => {
218 - let expectedCount = 0;
219 - let syntheticEvent;
223 + const eventHandler = e => {
224 + syntheticEvent = e;
225 + expectedCount++;
226 + };
227 + const node = ReactDOM.render(<div onClick={eventHandler} />, container);
228
221 - const eventHandler = e => {
222 - syntheticEvent = e;
223 - expectedCount++;
224 - };
225 - const node = ReactDOM.render(<div onClick={eventHandler} />, container);
229 + const event = document.createEvent('Event');
230 + event.initEvent('click', true, true);
231
227 - const event = document.createEvent('Event');
228 - event.initEvent('click', true, true);
232 + node.dispatchEvent(event);
233
230 - node.dispatchEvent(event);
234 + expect(() =>
235 + syntheticEvent.stopPropagation(),
236 + ).toErrorDev(
237 + 'Warning: This synthetic event is reused for performance reasons. If ' +
238 + "you're seeing this, you're accessing the method `stopPropagation` on a " +
239 + 'released/nullified synthetic event. This is a no-op function. If you must ' +
240 + 'keep the original synthetic event around, use event.persist(). ' +
241 + 'See https://fb.me/react-event-pooling for more information.',
242 + {withoutStack: true},
243 + );
244 + expect(expectedCount).toBe(1);
245 + });
246
232 - expect(() =>
233 - syntheticEvent.stopPropagation(),
234 - ).toErrorDev(
235 - 'Warning: This synthetic event is reused for performance reasons. If ' +
236 - "you're seeing this, you're accessing the method `stopPropagation` on a " +
237 - 'released/nullified synthetic event. This is a no-op function. If you must ' +
238 - 'keep the original synthetic event around, use event.persist(). ' +
239 - 'See https://fb.me/react-event-pooling for more information.',
240 - {withoutStack: true},
241 - );
242 - expect(expectedCount).toBe(1);
243 - });
247 + it('should warn when calling `isPropagationStopped` if the synthetic event has not been persisted', () => {
248 + let expectedCount = 0;
249 + let syntheticEvent;
250
245 - it('should warn when calling `isPropagationStopped` if the synthetic event has not been persisted', () => {
246 - let expectedCount = 0;
247 - let syntheticEvent;
251 + const eventHandler = e => {
252 + syntheticEvent = e;
253 + expectedCount++;
254 + };
255 + const node = ReactDOM.render(<div onClick={eventHandler} />, container);
256
249 - const eventHandler = e => {
250 - syntheticEvent = e;
251 - expectedCount++;
252 - };
253 - const node = ReactDOM.render(<div onClick={eventHandler} />, container);
257 + const event = document.createEvent('Event');
258 + event.initEvent('click', true, true);
259 + node.dispatchEvent(event);
260
255 - const event = document.createEvent('Event');
256 - event.initEvent('click', true, true);
257 - node.dispatchEvent(event);
261 + expect(() =>
262 + expect(syntheticEvent.isPropagationStopped()).toBe(false),
263 + ).toErrorDev(
264 + 'Warning: This synthetic event is reused for performance reasons. If ' +
265 + "you're seeing this, you're accessing the method `isPropagationStopped` on a " +
266 + 'released/nullified synthetic event. This is a no-op function. If you must ' +
267 + 'keep the original synthetic event around, use event.persist(). ' +
268 + 'See https://fb.me/react-event-pooling for more information.',
269 + {withoutStack: true},
270 + );
271 + expect(expectedCount).toBe(1);
272 + });
273
259 - expect(() =>
260 - expect(syntheticEvent.isPropagationStopped()).toBe(false),
261 - ).toErrorDev(
262 - 'Warning: This synthetic event is reused for performance reasons. If ' +
263 - "you're seeing this, you're accessing the method `isPropagationStopped` on a " +
264 - 'released/nullified synthetic event. This is a no-op function. If you must ' +
265 - 'keep the original synthetic event around, use event.persist(). ' +
266 - 'See https://fb.me/react-event-pooling for more information.',
267 - {withoutStack: true},
268 - );
269 - expect(expectedCount).toBe(1);
270 - });
274 + it('should warn when calling `isDefaultPrevented` if the synthetic event has not been persisted', () => {
275 + let expectedCount = 0;
276 + let syntheticEvent;
277
272 - it('should warn when calling `isDefaultPrevented` if the synthetic event has not been persisted', () => {
273 - let expectedCount = 0;
274 - let syntheticEvent;
278 + const eventHandler = e => {
279 + syntheticEvent = e;
280 + expectedCount++;
281 + };
282 + const node = ReactDOM.render(<div onClick={eventHandler} />, container);
283
276 - const eventHandler = e => {
277 - syntheticEvent = e;
278 - expectedCount++;
279 - };
280 - const node = ReactDOM.render(<div onClick={eventHandler} />, container);
284 + const event = document.createEvent('Event');
285 + event.initEvent('click', true, true);
286 + node.dispatchEvent(event);
287
282 - const event = document.createEvent('Event');
283 - event.initEvent('click', true, true);
284 - node.dispatchEvent(event);
288 + expect(() =>
289 + expect(syntheticEvent.isDefaultPrevented()).toBe(false),
290 + ).toErrorDev(
291 + 'Warning: This synthetic event is reused for performance reasons. If ' +
292 + "you're seeing this, you're accessing the method `isDefaultPrevented` on a " +
293 + 'released/nullified synthetic event. This is a no-op function. If you must ' +
294 + 'keep the original synthetic event around, use event.persist(). ' +
295 + 'See https://fb.me/react-event-pooling for more information.',
296 + {withoutStack: true},
297 + );
298 + expect(expectedCount).toBe(1);
299 + });
300
286 - expect(() =>
287 - expect(syntheticEvent.isDefaultPrevented()).toBe(false),
288 - ).toErrorDev(
289 - 'Warning: This synthetic event is reused for performance reasons. If ' +
290 - "you're seeing this, you're accessing the method `isDefaultPrevented` on a " +
291 - 'released/nullified synthetic event. This is a no-op function. If you must ' +
292 - 'keep the original synthetic event around, use event.persist(). ' +
293 - 'See https://fb.me/react-event-pooling for more information.',
294 - {withoutStack: true},
295 - );
296 - expect(expectedCount).toBe(1);
297 - });
301 + it('should properly log warnings when events simulated with rendered components', () => {
302 + let event;
303 + function assignEvent(e) {
304 + event = e;
305 + }
306 + const node = ReactDOM.render(<div onClick={assignEvent} />, container);
307 + node.click();
308
299 - it('should properly log warnings when events simulated with rendered components', () => {
300 - let event;
301 - function assignEvent(e) {
302 - event = e;
303 - }
304 - const node = ReactDOM.render(<div onClick={assignEvent} />, container);
305 - node.click();
306 -
307 - // access a property to cause the warning
308 - expect(() => {
309 - event.nativeEvent; // eslint-disable-line no-unused-expressions
310 - }).toErrorDev(
311 - 'Warning: This synthetic event is reused for performance reasons. If ' +
312 - "you're seeing this, you're accessing the property `nativeEvent` on a " +
313 - 'released/nullified synthetic event. This is set to null. If you must ' +
314 - 'keep the original synthetic event around, use event.persist(). ' +
315 - 'See https://fb.me/react-event-pooling for more information.',
316 - {withoutStack: true},
317 - );
318 - });
309 + // access a property to cause the warning
310 + expect(() => {
311 + event.nativeEvent; // eslint-disable-line no-unused-expressions
312 + }).toErrorDev(
313 + 'Warning: This synthetic event is reused for performance reasons. If ' +
314 + "you're seeing this, you're accessing the property `nativeEvent` on a " +
315 + 'released/nullified synthetic event. This is set to null. If you must ' +
316 + 'keep the original synthetic event around, use event.persist(). ' +
317 + 'See https://fb.me/react-event-pooling for more information.',
318 + {withoutStack: true},
319 + );
320 + });
321 + }
322
323 // TODO: we might want to re-add a warning like this in the future,
324 // but it shouldn't use Proxies because they make debugging difficult.
packages/react-dom/src/events/__tests__/SyntheticKeyboardEvent-test.js
+46 -43
@@ -11,6 +11,7 @@
11
12 let React;
13 let ReactDOM;
14 +const ReactFeatureFlags = require('shared/ReactFeatureFlags');
15
16 describe('SyntheticKeyboardEvent', () => {
17 let container;
@@ -547,49 +548,51 @@ describe('SyntheticKeyboardEvent', () => {
548 expect(expectedCount).toBe(3);
549 });
550
550 - it('is able to `persist`', () => {
551 - const persistentEvents = [];
552 - const eventHandler = event => {
553 - expect(event.isPersistent()).toBe(false);
554 - event.persist();
555 - expect(event.isPersistent()).toBe(true);
556 - persistentEvents.push(event);
557 - };
558 - const div = ReactDOM.render(
559 - <div
560 - onKeyDown={eventHandler}
561 - onKeyUp={eventHandler}
562 - onKeyPress={eventHandler}
563 - />,
564 - container,
565 - );
551 + if (!ReactFeatureFlags.enableModernEventSystem) {
552 + it('is able to `persist`', () => {
553 + const persistentEvents = [];
554 + const eventHandler = event => {
555 + expect(event.isPersistent()).toBe(false);
556 + event.persist();
557 + expect(event.isPersistent()).toBe(true);
558 + persistentEvents.push(event);
559 + };
560 + const div = ReactDOM.render(
561 + <div
562 + onKeyDown={eventHandler}
563 + onKeyUp={eventHandler}
564 + onKeyPress={eventHandler}
565 + />,
566 + container,
567 + );
568
567 - div.dispatchEvent(
568 - new KeyboardEvent('keydown', {
569 - keyCode: 40,
570 - bubbles: true,
571 - cancelable: true,
572 - }),
573 - );
574 - div.dispatchEvent(
575 - new KeyboardEvent('keyup', {
576 - keyCode: 40,
577 - bubbles: true,
578 - cancelable: true,
579 - }),
580 - );
581 - div.dispatchEvent(
582 - new KeyboardEvent('keypress', {
583 - charCode: 40,
584 - keyCode: 40,
585 - bubbles: true,
586 - cancelable: true,
587 - }),
588 - );
589 - expect(persistentEvents.length).toBe(3);
590 - expect(persistentEvents[0].type).toBe('keydown');
591 - expect(persistentEvents[1].type).toBe('keyup');
592 - expect(persistentEvents[2].type).toBe('keypress');
593 - });
569 + div.dispatchEvent(
570 + new KeyboardEvent('keydown', {
571 + keyCode: 40,
572 + bubbles: true,
573 + cancelable: true,
574 + }),
575 + );
576 + div.dispatchEvent(
577 + new KeyboardEvent('keyup', {
578 + keyCode: 40,
579 + bubbles: true,
580 + cancelable: true,
581 + }),
582 + );
583 + div.dispatchEvent(
584 + new KeyboardEvent('keypress', {
585 + charCode: 40,
586 + keyCode: 40,
587 + bubbles: true,
588 + cancelable: true,
589 + }),
590 + );
591 + expect(persistentEvents.length).toBe(3);
592 + expect(persistentEvents[0].type).toBe('keydown');
593 + expect(persistentEvents[1].type).toBe('keyup');
594 + expect(persistentEvents[2].type).toBe('keypress');
595 + });
596 + }
597 });
598 });
packages/react-dom/src/events/__tests__/SyntheticWheelEvent-test.js
+22 -19
@@ -11,6 +11,7 @@
11
12 let React;
13 let ReactDOM;
14 +const ReactFeatureFlags = require('shared/ReactFeatureFlags');
15
16 describe('SyntheticWheelEvent', () => {
17 let container;
@@ -113,23 +114,25 @@ describe('SyntheticWheelEvent', () => {
114 expect(events.length).toBe(2);
115 });
116
116 - it('should be able to `persist`', () => {
117 - const events = [];
118 - const onWheel = event => {
119 - expect(event.isPersistent()).toBe(false);
120 - event.persist();
121 - expect(event.isPersistent()).toBe(true);
122 - events.push(event);
123 - };
124 - ReactDOM.render(<div onWheel={onWheel} />, container);
125 -
126 - container.firstChild.dispatchEvent(
127 - new MouseEvent('wheel', {
128 - bubbles: true,
129 - }),
130 - );
131 -
132 - expect(events.length).toBe(1);
133 - expect(events[0].type).toBe('wheel');
134 - });
117 + if (!ReactFeatureFlags.enableModernEventSystem) {
118 + it('should be able to `persist`', () => {
119 + const events = [];
120 + const onWheel = event => {
121 + expect(event.isPersistent()).toBe(false);
122 + event.persist();
123 + expect(event.isPersistent()).toBe(true);
124 + events.push(event);
125 + };
126 + ReactDOM.render(<div onWheel={onWheel} />, container);
127 +
128 + container.firstChild.dispatchEvent(
129 + new MouseEvent('wheel', {
130 + bubbles: true,
131 + }),
132 + );
133 +
134 + expect(events.length).toBe(1);
135 + expect(events[0].type).toBe('wheel');
136 + });
137 + }
138 });