@samitouri / QOS-React-2 / commits / 50a0d69961

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