Skip to content

Commit 8e102ef

Browse files
jimfbjim
authored andcommitted
Add warning for unknown properties.
1 parent 799eae2 commit 8e102ef

File tree

3 files changed

+106
-41
lines changed

3 files changed

+106
-41
lines changed

src/addons/transitions/ReactTransitionGroup.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,9 +256,21 @@ var ReactTransitionGroup = React.createClass({
256256
));
257257
}
258258
}
259+
260+
// Do not forward ReactTransitionGroup props to primitive DOM nodes
261+
var props = Object.assign({}, this.props);
262+
delete props.transitionLeave;
263+
delete props.transitionName;
264+
delete props.transitionAppear;
265+
delete props.transitionEnter;
266+
delete props.childFactory;
267+
delete props.transitionLeaveTimeout;
268+
delete props.transitionEnterTimeout;
269+
delete props.component;
270+
259271
return React.createElement(
260272
this.props.component,
261-
this.props,
273+
props,
262274
childrenToRender
263275
);
264276
},

src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,20 @@ describe('ReactDOMComponent', function() {
148148
expect(console.error.argsForCall.length).toBe(2);
149149
});
150150

151+
it('should warn for unknown prop', function() {
152+
spyOn(console, 'error');
153+
var container = document.createElement('div');
154+
ReactDOM.render(<div foo="bar" />, container);
155+
expect(console.error.argsForCall.length).toBe(1);
156+
expect(console.error.argsForCall[0][0]).toContain(
157+
'Warning: Unknown prop `foo` on <div> tag. Remove this prop from the element. ' +
158+
'For details, see https://fb.me/react-unknown-prop'
159+
);
160+
expect(console.error.argsForCall[0][0]).toContain(
161+
'ReactDOMComponent-test.js'
162+
);
163+
});
164+
151165
it('should warn about styles with numeric string values for non-unitless properties', function() {
152166
spyOn(console, 'error');
153167

@@ -1332,15 +1346,25 @@ describe('ReactDOMComponent', function() {
13321346
ReactDOMServer.renderToString(<input type="text" onclick="1"/>);
13331347
expect(console.error.argsForCall.length).toBe(2);
13341348
expect(
1335-
console.error.argsForCall[0][0].replace(/\(.+?:\d+\)/g, '(**:*)')
1336-
).toBe(
1337-
'Warning: Unknown DOM property class. Did you mean className? (**:*)'
1349+
console.error.argsForCall[0][0]
1350+
).toContain(
1351+
'Warning: Unknown DOM property class. Did you mean className?'
13381352
);
13391353
expect(
1340-
console.error.argsForCall[1][0].replace(/\(.+?:\d+\)/g, '(**:*)')
1341-
).toBe(
1354+
console.error.argsForCall[0][0]
1355+
).toContain(
1356+
'ReactDOMComponent-test.js'
1357+
);
1358+
expect(
1359+
console.error.argsForCall[1][0]
1360+
).toContain(
13421361
'Warning: Unknown event handler property onclick. Did you mean ' +
1343-
'`onClick`? (**:*)'
1362+
'`onClick`?'
1363+
);
1364+
expect(
1365+
console.error.argsForCall[1][0]
1366+
).toContain(
1367+
'ReactDOMComponent-test.js'
13441368
);
13451369
});
13461370

@@ -1354,9 +1378,14 @@ describe('ReactDOMComponent', function() {
13541378
ReactDOMServer.renderToString(<div class="paladin" />, container);
13551379
expect(console.error.argsForCall.length).toBe(1);
13561380
expect(
1357-
console.error.argsForCall[0][0].replace(/\(.+?:\d+\)/g, '(**:*)')
1358-
).toBe(
1359-
'Warning: Unknown DOM property class. Did you mean className? (**:*)'
1381+
console.error.argsForCall[0][0]
1382+
).toContain(
1383+
'Warning: Unknown DOM property class. Did you mean className?'
1384+
);
1385+
expect(
1386+
console.error.argsForCall[0][0]
1387+
).toContain(
1388+
'ReactDOMComponent-test.js'
13601389
);
13611390
});
13621391

@@ -1375,10 +1404,12 @@ describe('ReactDOMComponent', function() {
13751404

13761405
expect(console.error.argsForCall.length).toBe(2);
13771406

1378-
var matches = console.error.argsForCall[0][0].match(/.*className.*\(.*:(\d+)\)/);
1407+
expect(console.error.argsForCall[0][0]).toContain('className');
1408+
var matches = console.error.argsForCall[0][0].match(/.*\(.*:(\d+)\).*/);
13791409
var previousLine = matches[1];
13801410

1381-
matches = console.error.argsForCall[1][0].match(/.*onClick.*\(.*:(\d+)\)/);
1411+
expect(console.error.argsForCall[1][0]).toContain('onClick');
1412+
matches = console.error.argsForCall[1][0].match(/.*\(.*:(\d+)\).*/);
13821413
var currentLine = matches[1];
13831414

13841415
//verify line number has a proper relative difference,
@@ -1424,10 +1455,12 @@ describe('ReactDOMComponent', function() {
14241455

14251456
expect(console.error.argsForCall.length).toBe(2);
14261457

1427-
var matches = console.error.argsForCall[0][0].match(/.*className.*\(.*:(\d+)\)/);
1458+
expect(console.error.argsForCall[0][0]).toContain('className');
1459+
var matches = console.error.argsForCall[0][0].match(/.*\(.*:(\d+)\).*/);
14281460
var previousLine = matches[1];
14291461

1430-
matches = console.error.argsForCall[1][0].match(/.*onClick.*\(.*:(\d+)\)/);
1462+
expect(console.error.argsForCall[1][0]).toContain('onClick');
1463+
matches = console.error.argsForCall[1][0].match(/.*\(.*:(\d+)\).*/);
14311464
var currentLine = matches[1];
14321465

14331466
//verify line number has a proper relative difference,

src/renderers/dom/shared/devtools/ReactDOMUnknownPropertyDevtool.js

Lines changed: 47 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
var DOMProperty = require('DOMProperty');
1515
var EventPluginRegistry = require('EventPluginRegistry');
16+
var ReactComponentTreeDevtool = require('ReactComponentTreeDevtool');
1617

1718
var warning = require('warning');
1819

@@ -22,10 +23,19 @@ if (__DEV__) {
2223
dangerouslySetInnerHTML: true,
2324
key: true,
2425
ref: true,
26+
27+
defaultValue: true,
28+
valueLink: true,
29+
defaultChecked: true,
30+
checkedLink: true,
31+
innerHTML: true,
32+
suppressContentEditableWarning: true,
33+
onFocusIn: true,
34+
onFocusOut: true,
2535
};
2636
var warnedProperties = {};
2737

28-
var warnUnknownProperty = function(name, source) {
38+
var warnUnknownProperty = function(tagName, name, source, debugID) {
2939
if (DOMProperty.properties.hasOwnProperty(name) || DOMProperty.isCustomAttribute(name)) {
3040
return;
3141
}
@@ -48,16 +58,6 @@ if (__DEV__) {
4858
null
4959
);
5060

51-
// For now, only warn when we have a suggested correction. This prevents
52-
// logging too much when using transferPropsTo.
53-
warning(
54-
standardName == null,
55-
'Unknown DOM property %s. Did you mean %s? %s',
56-
name,
57-
standardName,
58-
formatSource(source)
59-
);
60-
6161
var registrationName = (
6262
EventPluginRegistry.possibleRegistrationNames.hasOwnProperty(
6363
lowerCasedName
@@ -66,36 +66,56 @@ if (__DEV__) {
6666
null
6767
);
6868

69-
warning(
70-
registrationName == null,
71-
'Unknown event handler property %s. Did you mean `%s`? %s',
72-
name,
73-
registrationName,
74-
formatSource(source)
75-
);
76-
};
77-
78-
var formatSource = function(source) {
79-
return source ? `(${source.fileName.replace(/^.*[\\\/]/, '')}:${source.lineNumber})` : '';
69+
if (standardName != null) {
70+
warning(
71+
standardName == null,
72+
'Unknown DOM property %s. Did you mean %s? %s',
73+
name,
74+
standardName,
75+
ReactComponentTreeDevtool.getStackAddendumByID(debugID)
76+
);
77+
} else if (registrationName != null) {
78+
warning(
79+
registrationName == null,
80+
'Unknown event handler property %s. Did you mean `%s`? %s',
81+
name,
82+
registrationName,
83+
ReactComponentTreeDevtool.getStackAddendumByID(debugID)
84+
);
85+
} else {
86+
// We were unable to guess which prop the user intended.
87+
// It is likely that the user was just blindly spreading/forwarding props
88+
// Components should be careful to only render valid props/attributes.
89+
warning(
90+
tagName.indexOf('-') >= 0,
91+
'Unknown prop `%s` on <%s> tag. Remove this prop from the element. ' +
92+
'For details, see https://fb.me/react-unknown-prop %s',
93+
name,
94+
tagName,
95+
ReactComponentTreeDevtool.getStackAddendumByID(debugID)
96+
);
97+
}
8098
};
81-
8299
}
83100

84-
function handleElement(element) {
101+
function handleElement(debugID, element) {
85102
if (element == null || typeof element.type !== 'string') {
86103
return;
87104
}
105+
if (element.props.is) {
106+
return;
107+
}
88108
for (var key in element.props) {
89-
warnUnknownProperty(key, element._source);
109+
warnUnknownProperty(element.type, key, element._source, debugID);
90110
}
91111
}
92112

93113
var ReactDOMUnknownPropertyDevtool = {
94114
onBeforeMountComponent(debugID, element) {
95-
handleElement(element);
115+
handleElement(debugID, element);
96116
},
97117
onBeforeUpdateComponent(debugID, element) {
98-
handleElement(element);
118+
handleElement(debugID, element);
99119
},
100120
};
101121

0 commit comments

Comments
 (0)