Protect better against createElement(null/undefined)
This adds a warning to React.createElement in __DEV__ about using null or undefined. This is technically valid since element creation can be considered safe and usable in multiple rendering environments. But rendering in a DOM environment with an element with null/undefined type is not safe.
Paul O’Shannessy committed
Dec 16, 2014 at 13:57 UTC
50a0d6996112376d6d11e06103bb9acf8533fd43
3 files changed
+51
-17
src/classic/element/ReactElement.js
+1
-1
@@ -179,7 +179,7 @@ ReactElement.createElement = function(type, config, children) {
179
}
180
181
// Resolve default props
182
- if (type.defaultProps) {
182
+ if (type && type.defaultProps) {
183
var defaultProps = type.defaultProps;
184
for (propName in defaultProps) {
185
if (typeof props[propName] === 'undefined') {
src/classic/element/ReactElementValidator.js
+28
-16
@@ -24,6 +24,7 @@ var ReactCurrentOwner = require('ReactCurrentOwner');
24
25
var getIteratorFn = require('getIteratorFn');
26
var monitorCodeUse = require('monitorCodeUse');
27
+var warning = require('warning');
28
29
/**
30
* Warn if there's no key explicitly set on dynamic arrays of children or
@@ -239,6 +240,15 @@ function checkPropTypes(componentName, propTypes, props, location) {
240
var ReactElementValidator = {
241
242
createElement: function(type, props, children) {
243
+ // We warn in this case but don't throw. We expect the element creation to
244
+ // succeed and there will likely be errors in render.
245
+ warning(
246
+ type != null,
247
+ 'React.createElement: type should not be null or undefined. It should ' +
248
+ 'be a string (for DOM elements) or a ReactClass (for composite ' +
249
+ 'components).'
250
+ );
251
+
252
var element = ReactElement.createElement.apply(this, arguments);
253
254
// The result can be nullish if a mock or a custom function is used.
@@ -251,22 +261,24 @@ var ReactElementValidator = {
261
validateChildKeys(arguments[i], type);
262
}
263
254
- var name = type.displayName;
255
- if (type.propTypes) {
256
- checkPropTypes(
257
- name,
258
- type.propTypes,
259
- element.props,
260
- ReactPropTypeLocations.prop
261
- );
262
- }
263
- if (type.contextTypes) {
264
- checkPropTypes(
265
- name,
266
- type.contextTypes,
267
- element._context,
268
- ReactPropTypeLocations.context
269
- );
264
+ if (type) {
265
+ var name = type.displayName;
266
+ if (type.propTypes) {
267
+ checkPropTypes(
268
+ name,
269
+ type.propTypes,
270
+ element.props,
271
+ ReactPropTypeLocations.prop
272
+ );
273
+ }
274
+ if (type.contextTypes) {
275
+ checkPropTypes(
276
+ name,
277
+ type.contextTypes,
278
+ element._context,
279
+ ReactPropTypeLocations.context
280
+ );
281
+ }
282
}
283
return element;
284
},
src/classic/element/__tests__/ReactElementValidator-test.js
+22
@@ -55,6 +55,28 @@ describe('ReactElementValidator', function() {
55
);
56
});
57
58
+ it('gives a helpful error when passing null or undefined', function() {
59
+ spyOn(console, 'warn');
60
+ React.createElement(undefined);
61
+ React.createElement(null);
62
+ expect(console.warn.calls.length).toBe(2);
63
+ expect(console.warn.calls[0].args[0]).toBe(
64
+ 'Warning: React.createElement: type should not be null or undefined. ' +
65
+ 'It should be a string (for DOM elements) or a ReactClass (for ' +
66
+ 'composite components).'
67
+ );
68
+ expect(console.warn.calls[1].args[0]).toBe(
69
+ 'Warning: React.createElement: type should not be null or undefined. ' +
70
+ 'It should be a string (for DOM elements) or a ReactClass (for ' +
71
+ 'composite components).'
72
+ );
73
+ React.createElement('div');
74
+ expect(console.warn.calls.length).toBe(2);
75
+
76
+ expect(() => React.createElement(undefined)).not.toThrow()
77
+ });
78
+
79
+
80
it('should check default prop values', function() {
81
spyOn(console, 'warn');
82