Skip to content

Commit 5926341

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

File tree

3 files changed

+90
-38
lines changed

3 files changed

+90
-38
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: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ describe('ReactDOMComponent', function() {
1919
var ReactDOMServer;
2020
var inputValueTracking;
2121

22+
function normalizeCodeLocInfo(str) {
23+
return str.replace(/\(at .+?:\d+\)/g, '(at **)');
24+
}
25+
2226
beforeEach(function() {
2327
jest.resetModuleRegistry();
2428
React = require('React');
@@ -148,6 +152,17 @@ describe('ReactDOMComponent', function() {
148152
expect(console.error.argsForCall.length).toBe(2);
149153
});
150154

155+
it('should warn for unknown prop', function() {
156+
spyOn(console, 'error');
157+
var container = document.createElement('div');
158+
ReactDOM.render(<div foo="bar" />, container);
159+
expect(console.error.argsForCall.length).toBe(1);
160+
expect(normalizeCodeLocInfo(console.error.argsForCall[0][0])).toBe(
161+
'Warning: Unknown prop `foo` on <div> tag. Remove this prop from the element. ' +
162+
'For details, see https://fb.me/react-unknown-prop\n in div (at **)'
163+
);
164+
});
165+
151166
it('should warn about styles with numeric string values for non-unitless properties', function() {
152167
spyOn(console, 'error');
153168

@@ -1332,15 +1347,15 @@ describe('ReactDOMComponent', function() {
13321347
ReactDOMServer.renderToString(<input type="text" onclick="1"/>);
13331348
expect(console.error.argsForCall.length).toBe(2);
13341349
expect(
1335-
console.error.argsForCall[0][0].replace(/\(.+?:\d+\)/g, '(**:*)')
1350+
normalizeCodeLocInfo(console.error.argsForCall[0][0])
13361351
).toBe(
1337-
'Warning: Unknown DOM property class. Did you mean className? (**:*)'
1352+
'Warning: Unknown DOM property class. Did you mean className?\n in div (at **)'
13381353
);
13391354
expect(
1340-
console.error.argsForCall[1][0].replace(/\(.+?:\d+\)/g, '(**:*)')
1355+
normalizeCodeLocInfo(console.error.argsForCall[1][0])
13411356
).toBe(
13421357
'Warning: Unknown event handler property onclick. Did you mean ' +
1343-
'`onClick`? (**:*)'
1358+
'`onClick`?\n in input (at **)'
13441359
);
13451360
});
13461361

@@ -1354,10 +1369,11 @@ describe('ReactDOMComponent', function() {
13541369
ReactDOMServer.renderToString(<div class="paladin" />, container);
13551370
expect(console.error.argsForCall.length).toBe(1);
13561371
expect(
1357-
console.error.argsForCall[0][0].replace(/\(.+?:\d+\)/g, '(**:*)')
1372+
normalizeCodeLocInfo(console.error.argsForCall[0][0])
13581373
).toBe(
1359-
'Warning: Unknown DOM property class. Did you mean className? (**:*)'
1374+
'Warning: Unknown DOM property class. Did you mean className?\n in div (at **)'
13601375
);
1376+
13611377
});
13621378

13631379
it('gives source code refs for unknown prop warning for exact elements ', function() {
@@ -1375,10 +1391,12 @@ describe('ReactDOMComponent', function() {
13751391

13761392
expect(console.error.argsForCall.length).toBe(2);
13771393

1378-
var matches = console.error.argsForCall[0][0].match(/.*className.*\(.*:(\d+)\)/);
1394+
expect(console.error.argsForCall[0][0]).toContain('className');
1395+
var matches = console.error.argsForCall[0][0].match(/.*\(.*:(\d+)\).*/);
13791396
var previousLine = matches[1];
13801397

1381-
matches = console.error.argsForCall[1][0].match(/.*onClick.*\(.*:(\d+)\)/);
1398+
expect(console.error.argsForCall[1][0]).toContain('onClick');
1399+
matches = console.error.argsForCall[1][0].match(/.*\(.*:(\d+)\).*/);
13821400
var currentLine = matches[1];
13831401

13841402
//verify line number has a proper relative difference,
@@ -1424,10 +1442,12 @@ describe('ReactDOMComponent', function() {
14241442

14251443
expect(console.error.argsForCall.length).toBe(2);
14261444

1427-
var matches = console.error.argsForCall[0][0].match(/.*className.*\(.*:(\d+)\)/);
1445+
expect(console.error.argsForCall[0][0]).toContain('className');
1446+
var matches = console.error.argsForCall[0][0].match(/.*\(.*:(\d+)\).*/);
14281447
var previousLine = matches[1];
14291448

1430-
matches = console.error.argsForCall[1][0].match(/.*onClick.*\(.*:(\d+)\)/);
1449+
expect(console.error.argsForCall[1][0]).toContain('onClick');
1450+
matches = console.error.argsForCall[1][0].match(/.*\(.*:(\d+)\).*/);
14311451
var currentLine = matches[1];
14321452

14331453
//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, 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+
false,
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.type.indexOf('-') >= 0 || element.props.is) {
106+
return;
107+
}
88108
for (var key in element.props) {
89-
warnUnknownProperty(key, element._source);
109+
warnUnknownProperty(element.type, key, 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)