diff --git a/src/isomorphic/classic/element/ReactElement.js b/src/isomorphic/classic/element/ReactElement.js index e95941846c789..f9a26a71949ca 100644 --- a/src/isomorphic/classic/element/ReactElement.js +++ b/src/isomorphic/classic/element/ReactElement.js @@ -14,6 +14,7 @@ var ReactCurrentOwner = require('ReactCurrentOwner'); var assign = require('Object.assign'); +var warning = require('warning'); var canDefineProperty = require('canDefineProperty'); // The Symbol used to tag the ReactElement type. If there is no native Symbol @@ -159,6 +160,37 @@ ReactElement.createElement = function(type, config, children) { } } + if (__DEV__) { + // Create dummy `key` and `ref` property to `props` to warn users + // against its use + Object.defineProperty(props, 'key', { + get: function () { + warning( + false, + '%s: `key` is not a prop. Trying to access it will result ' + + 'in `undefined` being returned. If you need to access the same ' + + 'value within the child component, you should pass it as a different ' + + 'prop. (http://stackoverflow.com/questions/33682774/how-to-access-the' + + '-key-property-from-a-reactjs-component)', + 'displayName' in type ? type.displayName: 'Element' + ); + } + }); + Object.defineProperty(props, 'ref', { + get: function () { + warning( + false, + '%s: `ref` is not a prop. Trying to access it will result ' + + 'in `undefined` being returned. If you need to access the same ' + + 'value within the child component, you should pass it as a different ' + + 'prop. (http://stackoverflow.com/questions/33682774/how-to-access-the' + + '-key-property-from-a-reactjs-component)', + 'displayName' in type ? type.displayName: 'Element' + ); + } + }); + } + return ReactElement( type, key, diff --git a/src/isomorphic/classic/element/__tests__/ReactElement-test.js b/src/isomorphic/classic/element/__tests__/ReactElement-test.js index b4a0bbd395eac..5b98f1f64d11d 100644 --- a/src/isomorphic/classic/element/__tests__/ReactElement-test.js +++ b/src/isomorphic/classic/element/__tests__/ReactElement-test.js @@ -58,6 +58,66 @@ describe('ReactElement', function() { expect(element.props).toEqual(expectation); }); + it('should warn when `key` is being accessed', function() { + spyOn(console, 'error'); + var container = document.createElement('div'); + var Child = React.createClass({ + render: function() { + return
{this.props.key}
+ }, + }); + var Parent = React.createClass({ + render: function() { + return ( +
+ + + +
+ ); + }, + }); + expect(console.error.calls.length).toBe(0); + ReactDOM.render(, container); + expect(console.error.calls.length).toBe(3); + expect(console.error.argsForCall[0][0]).toContain( + 'Child: `key` is not a prop. Trying to access it will result ' + + 'in `undefined` being returned. If you need to access the same ' + + 'value within the child component, you should pass it as a different ' + + 'prop. (http://stackoverflow.com/questions/33682774/how-to-access-the' + + '-key-property-from-a-reactjs-component)' + ); + }); + + it('should warn when `ref` is being accessed', function() { + spyOn(console, 'error'); + var container = document.createElement('div'); + var Child = React.createClass({ + render: function() { + return
{this.props.ref}
+ }, + }); + var Parent = React.createClass({ + render: function() { + return ( +
+ +
+ ); + }, + }); + expect(console.error.calls.length).toBe(0); + ReactDOM.render(, container); + expect(console.error.calls.length).toBe(1); + expect(console.error.argsForCall[0][0]).toContain( + 'Child: `ref` is not a prop. Trying to access it will result ' + + 'in `undefined` being returned. If you need to access the same ' + + 'value within the child component, you should pass it as a different ' + + 'prop. (http://stackoverflow.com/questions/33682774/how-to-access-the' + + '-key-property-from-a-reactjs-component)' + ); + }); + it('allows a string to be passed as the type', function() { var element = React.createFactory('div')(); expect(element.type).toBe('div');