mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Add a warning for adding some properties in the SyntheticEvent object if Proxy is supported
This commit is contained in:
@@ -34,7 +34,7 @@ var ClipboardEventInterface = {
|
||||
* @extends {SyntheticUIEvent}
|
||||
*/
|
||||
function SyntheticClipboardEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
|
||||
SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
}
|
||||
|
||||
SyntheticEvent.augmentClass(SyntheticClipboardEvent, ClipboardEventInterface);
|
||||
|
||||
@@ -33,7 +33,7 @@ function SyntheticCompositionEvent(
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
) {
|
||||
SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
}
|
||||
|
||||
SyntheticEvent.augmentClass(
|
||||
|
||||
@@ -28,7 +28,7 @@ var DragEventInterface = {
|
||||
* @extends {SyntheticUIEvent}
|
||||
*/
|
||||
function SyntheticDragEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
|
||||
SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
return SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
}
|
||||
|
||||
SyntheticMouseEvent.augmentClass(SyntheticDragEvent, DragEventInterface);
|
||||
|
||||
@@ -17,6 +17,19 @@ var assign = require('Object.assign');
|
||||
var emptyFunction = require('emptyFunction');
|
||||
var warning = require('warning');
|
||||
|
||||
var didWarnForAddedNewProperty = false;
|
||||
var isProxySupported = typeof Proxy === 'function';
|
||||
|
||||
var shouldBeReleasedProperties = [
|
||||
'dispatchConfig',
|
||||
'_targetInst',
|
||||
'nativeEvent',
|
||||
'isDefaultPrevented',
|
||||
'isPropagationStopped',
|
||||
'_dispatchListeners',
|
||||
'_dispatchInstances',
|
||||
];
|
||||
|
||||
/**
|
||||
* @interface Event
|
||||
* @see http://www.w3.org/TR/DOM-Level-3-Events/
|
||||
@@ -57,7 +70,7 @@ var EventInterface = {
|
||||
function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) {
|
||||
if (__DEV__) {
|
||||
// these have a getter/setter for warnings
|
||||
delete this.nativeEvent;
|
||||
delete this.nativeEvent;
|
||||
delete this.preventDefault;
|
||||
delete this.stopPropagation;
|
||||
}
|
||||
@@ -95,6 +108,7 @@ function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarg
|
||||
this.isDefaultPrevented = emptyFunction.thatReturnsFalse;
|
||||
}
|
||||
this.isPropagationStopped = emptyFunction.thatReturnsFalse;
|
||||
return this;
|
||||
}
|
||||
|
||||
assign(SyntheticEvent.prototype, {
|
||||
@@ -156,22 +170,52 @@ assign(SyntheticEvent.prototype, {
|
||||
this[propName] = null;
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < shouldBeReleasedProperties.length; i++) {
|
||||
this[shouldBeReleasedProperties[i]] = null;
|
||||
}
|
||||
if (__DEV__) {
|
||||
var noop = require('emptyFunction');
|
||||
Object.defineProperty(this, 'nativeEvent', getPooledWarningPropertyDefinition('nativeEvent', null));
|
||||
Object.defineProperty(this, 'preventDefault', getPooledWarningPropertyDefinition('preventDefault', noop));
|
||||
Object.defineProperty(this, 'stopPropagation', getPooledWarningPropertyDefinition('stopPropagation', noop));
|
||||
} else {
|
||||
this.nativeEvent = null;
|
||||
}
|
||||
this.dispatchConfig = null;
|
||||
this._targetInst = null;
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
SyntheticEvent.Interface = EventInterface;
|
||||
|
||||
if (__DEV__) {
|
||||
if (isProxySupported) {
|
||||
/*eslint-disable no-func-assign */
|
||||
SyntheticEvent = new Proxy(SyntheticEvent, {
|
||||
construct: function(target, args) {
|
||||
return this.apply(target, {}, args);
|
||||
},
|
||||
apply: function(constructor, that, args) {
|
||||
return new Proxy(constructor.apply(that, args), {
|
||||
set: function(target, prop, value) {
|
||||
if (prop !== 'isPersistent' &&
|
||||
!target.constructor.Interface.hasOwnProperty(prop) &&
|
||||
shouldBeReleasedProperties.indexOf(prop) === -1) {
|
||||
warning(
|
||||
didWarnForAddedNewProperty || target.isPersistent(),
|
||||
'This synthetic event is reused for performance reasons. If you\'re ' +
|
||||
'seeing this, you\'re adding a new property in the synthetic event object. ' +
|
||||
'The property is never released. See ' +
|
||||
'https://fb.me/react-event-pooling for more information.'
|
||||
);
|
||||
didWarnForAddedNewProperty = true;
|
||||
}
|
||||
target[prop] = value;
|
||||
return true;
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
/*eslint-enable no-func-assign */
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Helper to reduce boilerplate when creating subclasses.
|
||||
*
|
||||
|
||||
@@ -28,7 +28,7 @@ var FocusEventInterface = {
|
||||
* @extends {SyntheticUIEvent}
|
||||
*/
|
||||
function SyntheticFocusEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
|
||||
SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
}
|
||||
|
||||
SyntheticUIEvent.augmentClass(SyntheticFocusEvent, FocusEventInterface);
|
||||
|
||||
@@ -34,7 +34,7 @@ function SyntheticInputEvent(
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
) {
|
||||
SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
}
|
||||
|
||||
SyntheticEvent.augmentClass(
|
||||
|
||||
@@ -76,7 +76,7 @@ var KeyboardEventInterface = {
|
||||
* @extends {SyntheticUIEvent}
|
||||
*/
|
||||
function SyntheticKeyboardEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
|
||||
SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
}
|
||||
|
||||
SyntheticUIEvent.augmentClass(SyntheticKeyboardEvent, KeyboardEventInterface);
|
||||
|
||||
@@ -72,7 +72,7 @@ var MouseEventInterface = {
|
||||
* @extends {SyntheticUIEvent}
|
||||
*/
|
||||
function SyntheticMouseEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
|
||||
SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
}
|
||||
|
||||
SyntheticUIEvent.augmentClass(SyntheticMouseEvent, MouseEventInterface);
|
||||
|
||||
@@ -37,7 +37,7 @@ var TouchEventInterface = {
|
||||
* @extends {SyntheticUIEvent}
|
||||
*/
|
||||
function SyntheticTouchEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
|
||||
SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
}
|
||||
|
||||
SyntheticUIEvent.augmentClass(SyntheticTouchEvent, TouchEventInterface);
|
||||
|
||||
@@ -51,7 +51,7 @@ var UIEventInterface = {
|
||||
* @extends {SyntheticEvent}
|
||||
*/
|
||||
function SyntheticUIEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
|
||||
SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
}
|
||||
|
||||
SyntheticEvent.augmentClass(SyntheticUIEvent, UIEventInterface);
|
||||
|
||||
@@ -50,7 +50,7 @@ var WheelEventInterface = {
|
||||
* @extends {SyntheticMouseEvent}
|
||||
*/
|
||||
function SyntheticWheelEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
|
||||
SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
return SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
}
|
||||
|
||||
SyntheticMouseEvent.augmentClass(SyntheticWheelEvent, WheelEventInterface);
|
||||
|
||||
@@ -160,4 +160,23 @@ describe('SyntheticEvent', function() {
|
||||
'See https://fb.me/react-event-pooling for more information.'
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn if Proxy is supported and the synthetic event is added a property', function() {
|
||||
spyOn(console, 'error');
|
||||
var syntheticEvent = createEvent({});
|
||||
syntheticEvent.foo = 'bar';
|
||||
SyntheticEvent.release(syntheticEvent);
|
||||
expect(syntheticEvent.foo).toBe('bar');
|
||||
if (typeof Proxy === 'function') {
|
||||
expect(console.error.calls.length).toBe(1);
|
||||
expect(console.error.argsForCall[0][0]).toBe(
|
||||
'Warning: This synthetic event is reused for performance reasons. If you\'re ' +
|
||||
'seeing this, you\'re adding a new property in the synthetic event object. ' +
|
||||
'The property is never released. See ' +
|
||||
'https://fb.me/react-event-pooling for more information.'
|
||||
);
|
||||
} else {
|
||||
expect(console.error.calls.length).toBe(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user