mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Warns on access of props.key and props.ref
This commit is contained in:
@@ -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
|
||||
@@ -29,6 +30,8 @@ var RESERVED_PROPS = {
|
||||
__source: true,
|
||||
};
|
||||
|
||||
var specialPropKeyWarningShown, specialPropRefWarningShown;
|
||||
|
||||
/**
|
||||
* Factory method to create a new React element. This no longer adheres to
|
||||
* the class pattern, so do not use new to call it. Also, no instanceof check
|
||||
@@ -123,8 +126,15 @@ ReactElement.createElement = function(type, config, children) {
|
||||
var source = null;
|
||||
|
||||
if (config != null) {
|
||||
ref = config.ref === undefined ? null : config.ref;
|
||||
key = config.key === undefined ? null : '' + config.key;
|
||||
if (__DEV__) {
|
||||
ref = !config.hasOwnProperty('ref') ||
|
||||
Object.getOwnPropertyDescriptor(config, 'ref').get ? null : config.ref;
|
||||
key = !config.hasOwnProperty('key') ||
|
||||
Object.getOwnPropertyDescriptor(config, 'key').get ? null : '' + config.key;
|
||||
} else {
|
||||
ref = config.ref === undefined ? null : config.ref;
|
||||
key = config.key === undefined ? null : '' + config.key;
|
||||
}
|
||||
self = config.__self === undefined ? null : config.__self;
|
||||
source = config.__source === undefined ? null : config.__source;
|
||||
// Remaining properties are added to a new props object
|
||||
@@ -158,7 +168,51 @@ ReactElement.createElement = function(type, config, children) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
// Create dummy `key` and `ref` property to `props` to warn users
|
||||
// against its use
|
||||
if (typeof props.$$typeof === 'undefined' ||
|
||||
props.$$typeof !== REACT_ELEMENT_TYPE) {
|
||||
if (!props.hasOwnProperty('key')) {
|
||||
Object.defineProperty(props, 'key', {
|
||||
get: function() {
|
||||
if (!specialPropKeyWarningShown) {
|
||||
specialPropKeyWarningShown = true;
|
||||
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. (https://fb.me/react-special-props)',
|
||||
'displayName' in type ? type.displayName: 'Element'
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
if (!props.hasOwnProperty('ref')) {
|
||||
Object.defineProperty(props, 'ref', {
|
||||
get: function() {
|
||||
if (!specialPropRefWarningShown) {
|
||||
specialPropRefWarningShown = true;
|
||||
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. (https://fb.me/react-special-props)',
|
||||
'displayName' in type ? type.displayName: 'Element'
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return ReactElement(
|
||||
type,
|
||||
key,
|
||||
|
||||
@@ -58,6 +58,64 @@ 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 <div> {this.props.key} </div>;
|
||||
},
|
||||
});
|
||||
var Parent = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<Child key="0" />
|
||||
<Child key="1" />
|
||||
<Child key="2" />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
expect(console.error.calls.length).toBe(0);
|
||||
ReactDOM.render(<Parent />, container);
|
||||
expect(console.error.calls.length).toBe(1);
|
||||
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. (https://fb.me/react-special-props)'
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn when `ref` is being accessed', function() {
|
||||
spyOn(console, 'error');
|
||||
var container = document.createElement('div');
|
||||
var Child = React.createClass({
|
||||
render: function() {
|
||||
return <div> {this.props.ref} </div>;
|
||||
},
|
||||
});
|
||||
var Parent = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<Child ref="childElement" />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
expect(console.error.calls.length).toBe(0);
|
||||
ReactDOM.render(<Parent />, 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. (https://fb.me/react-special-props)'
|
||||
);
|
||||
});
|
||||
|
||||
it('allows a string to be passed as the type', function() {
|
||||
var element = React.createFactory('div')();
|
||||
expect(element.type).toBe('div');
|
||||
|
||||
Reference in New Issue
Block a user