Skip to content

Commit

Permalink
warn(SyntheticEvent): Warn when accessing or setting properties on re…
Browse files Browse the repository at this point in the history
…leased syntheticEvents
  • Loading branch information
Kent C. Dodds committed Jan 29, 2016
1 parent 9c3f595 commit e808985
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 9 deletions.
40 changes: 36 additions & 4 deletions src/renderers/dom/client/syntheticEvents/SyntheticEvent.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,45 @@ assign(SyntheticEvent.prototype, {
* `PooledClass` looks for `destructor` on each instance it releases.
*/
destructor: function() {
var setNull = setToNullOrWarning.bind(this)
var Interface = this.constructor.Interface;
for (var propName in Interface) {
this[propName] = null;
setNull(propName);
}
var otherProps = ['dispatchConfig', '_targetInst', 'nativeEvent'];
otherProps.forEach(setNull);

function setToNullOrWarning(propName) {
if (__DEV__) {
Object.defineProperty(this, propName, {
set: function(val) {
// no-op
var warningCondition = false;
warning(
warningCondition,
'This synthetic event is reused for performance reasons. If you\'re ' +
'seeing this, you\'re setting property `' + propName + '` on a ' +
'released/nullified synthetic event. This is effectively a no-op. See ' +
'https://fb.me/react-event-pooling for more information.'
);
return val;
},
get: function() {
var warningCondition = false;
warning(
warningCondition,
'This synthetic event is reused for performance reasons. If you\'re ' +
'seeing this, you\'re accessing property `' + propName + '` on a ' +
'released/nullified synthetic event. This is set to null. See ' +
'https://fb.me/react-event-pooling for more information.'
);
return null;
}
})
} else {
this[propName] = null;
}
}
this.dispatchConfig = null;
this._targetInst = null;
this.nativeEvent = null;
},

});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ describe('SyntheticEvent', function() {
});

it('should be nullified if the synthetic event has called destructor', function() {
spyOn(console, 'error');
var target = document.createElement('div');
var syntheticEvent = createEvent({srcElement: target});
syntheticEvent.destructor();
Expand All @@ -81,27 +82,57 @@ describe('SyntheticEvent', function() {
expect(syntheticEvent.target).toBe(null);
});

it('should warn when accessing properties of a destructored synthetic event', function() {
spyOn(console, 'error');
var target = document.createElement('div');
var syntheticEvent = createEvent({srcElement: target});
syntheticEvent.destructor();
expect(syntheticEvent.type).toBe(null);
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 accessing a property on a ' +
'released/nullified synthetic event. This is set to null. See ' +
'https://fb.me/react-event-pooling for more information.'
);
});

it('should warn when setting properties of a destructored synthetic event', function() {
spyOn(console, 'error');
var target = document.createElement('div');
var syntheticEvent = createEvent({srcElement: target});
syntheticEvent.destructor();
expect(syntheticEvent.type = 'MouseEvent').toBe('MouseEvent');
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 setting a property on a ' +
'released/nullified synthetic event. This is effectively a no-op. See ' +
'https://fb.me/react-event-pooling for more information.'
);
});

it('should warn if the synthetic event has been released when calling `preventDefault`', function() {
spyOn(console, 'error');
var syntheticEvent = createEvent({});
SyntheticEvent.release(syntheticEvent);
syntheticEvent.preventDefault();
expect(console.error.calls.length).toBe(1);
expect(console.error.argsForCall[0][0]).toBe(
expect(console.error.calls.length).toBe(3); // once each for setting `defaultPrevented`, accessing `nativeEvent`, and accessing `preventDefault`
expect(console.error.argsForCall[2][0]).toBe(
'Warning: This synthetic event is reused for performance reasons. If ' +
'you\'re seeing this, you\'re calling `preventDefault` on a ' +
'released/nullified synthetic event. This is a no-op. See ' +
'https://fb.me/react-event-pooling for more information.'
);
});

it('should warn if the synthetic event has been released when calling `stopPropagation`', function() {
iit('should warn if the synthetic event has been released when calling `stopPropagation`', function() {
spyOn(console, 'error');
var syntheticEvent = createEvent({});
SyntheticEvent.release(syntheticEvent);
syntheticEvent.stopPropagation();
expect(console.error.calls.length).toBe(1);
expect(console.error.argsForCall[0][0]).toBe(
expect(console.error.calls.length).toBe(2); // once each for accessing `nativeEvent` and accessing `setPropogation`
expect(console.error.argsForCall[1][0]).toBe(
'Warning: This synthetic event is reused for performance reasons. If ' +
'you\'re seeing this, you\'re calling `stopPropagation` on a ' +
'released/nullified synthetic event. This is a no-op. See ' +
Expand Down

0 comments on commit e808985

Please sign in to comment.