Move logic for `null` to instantiateReactComponent
This cleans up the code a bit and also brings us closer to allowing any ReactNode to be rendered at the top level. Test Plan: jest
Ben Alpert committed
Nov 15, 2014 at 13:02 UTC
a194e51af0c1f62d5b994f203c61bbe9a75e5c55
5 files changed
+28
-24
src/browser/ui/ReactMount.js
+1
-1
@@ -361,7 +361,7 @@ var ReactMount = {
361
' Instead of passing a component class, make sure to instantiate ' +
362
'it by passing it to React.createElement.' :
363
// Check if it quacks like an element
364
- typeof nextElement.props !== "undefined" ?
364
+ nextElement != null && nextElement.props !== undefined ?
365
' This may be caused by unintentionally loading two independent ' +
366
'copies of React.' :
367
''
src/core/ReactCompositeComponent.js
+2
-19
@@ -15,7 +15,6 @@ var ReactComponent = require('ReactComponent');
15
var ReactContext = require('ReactContext');
16
var ReactCurrentOwner = require('ReactCurrentOwner');
17
var ReactElement = require('ReactElement');
18
-var ReactEmptyComponent = require('ReactEmptyComponent');
18
var ReactInstanceMap = require('ReactInstanceMap');
19
var ReactOwner = require('ReactOwner');
20
var ReactPerf = require('ReactPerf');
@@ -197,10 +196,6 @@ var ReactCompositeComponentMixin = assign({},
196
}
197
198
var renderedElement = this._renderValidatedComponent();
200
- if (renderedElement === ReactEmptyComponent.emptyElement) {
201
- ReactEmptyComponent.registerNullComponentID(this._rootNodeID);
202
- }
203
-
199
this._renderedComponent = this._instantiateReactComponent(
200
renderedElement,
201
this._currentElement.type // The wrapping type
@@ -235,11 +230,6 @@ var ReactCompositeComponentMixin = assign({},
230
}
231
this._compositeLifeCycleState = null;
232
238
- if (this._renderedComponent._currentElement ===
239
- ReactEmptyComponent.emptyElement) {
240
- ReactEmptyComponent.deregisterNullComponentID(this._rootNodeID);
241
- }
242
-
233
this._renderedComponent.unmountComponent();
234
this._renderedComponent = null;
235
@@ -652,12 +642,6 @@ var ReactCompositeComponentMixin = assign({},
642
var prevComponentID = prevComponentInstance._rootNodeID;
643
prevComponentInstance.unmountComponent();
644
655
- if (nextRenderedElement === ReactEmptyComponent.emptyElement) {
656
- ReactEmptyComponent.registerNullComponentID(this._rootNodeID);
657
- } else if (prevRenderedElement === ReactEmptyComponent.emptyElement) {
658
- ReactEmptyComponent.deregisterNullComponentID(this._rootNodeID);
659
- }
660
-
645
this._renderedComponent = this._instantiateReactComponent(
646
nextRenderedElement,
647
this._currentElement.type
@@ -699,14 +683,13 @@ var ReactCompositeComponentMixin = assign({},
683
renderedComponent = null;
684
}
685
}
702
- if (renderedComponent === null || renderedComponent === false) {
703
- renderedComponent = ReactEmptyComponent.emptyElement;
704
- }
686
} finally {
687
ReactContext.current = previousContext;
688
ReactCurrentOwner.current = null;
689
}
690
invariant(
691
+ // TODO: An `isValidNode` function would probably be more appropriate
692
+ renderedComponent === null || renderedComponent === false ||
693
ReactElement.isValidElement(renderedComponent),
694
'%s.render(): A valid ReactComponent must be returned. You may have ' +
695
'returned undefined, an array or some other invalid object.',
src/core/ReactEmptyComponent.js
+10
-4
@@ -12,6 +12,7 @@
12
"use strict";
13
14
var ReactElement = require('ReactElement');
15
+var ReactInstanceMap = require('ReactInstanceMap');
16
17
var invariant = require('invariant');
18
@@ -27,6 +28,14 @@ var ReactEmptyComponentInjection = {
28
};
29
30
var ReactEmptyComponentType = function() {};
31
+ReactEmptyComponentType.prototype.componentDidMount = function() {
32
+ var internalInstance = ReactInstanceMap.get(this);
33
+ registerNullComponentID(internalInstance._rootNodeID);
34
+};
35
+ReactEmptyComponentType.prototype.componentWillUnmount = function() {
36
+ var internalInstance = ReactInstanceMap.get(this);
37
+ deregisterNullComponentID(internalInstance._rootNodeID);
38
+};
39
ReactEmptyComponentType.prototype.render = function() {
40
invariant(
41
component,
@@ -65,10 +74,7 @@ function isNullComponentID(id) {
74
var ReactEmptyComponent = {
75
emptyElement: emptyElement,
76
injection: ReactEmptyComponentInjection,
68
-
69
- deregisterNullComponentID: deregisterNullComponentID,
70
- isNullComponentID: isNullComponentID,
71
- registerNullComponentID: registerNullComponentID
77
+ isNullComponentID: isNullComponentID
78
};
79
80
module.exports = ReactEmptyComponent;
src/core/__tests__/ReactEmptyComponent-test.js
+10
@@ -221,5 +221,15 @@ describe('ReactEmptyComponent', function() {
221
222
expect(assertions).toBe(3);
223
});
224
+
225
+ it('throws when rendering null at the top level', function() {
226
+ // TODO: This should actually work since `null` is a valid ReactNode
227
+ var div = document.createElement('div');
228
+ expect(function() {
229
+ React.render(null, div);
230
+ }).toThrow(
231
+ 'Invariant Violation: renderComponent(): Invalid component element.'
232
+ );
233
+ });
234
});
235
src/core/instantiateReactComponent.js
+5
@@ -13,6 +13,7 @@
13
"use strict";
14
15
var ReactCompositeComponent = require('ReactCompositeComponent');
16
+var ReactEmptyComponent = require('ReactEmptyComponent');
17
var ReactNativeComponent = require('ReactNativeComponent');
18
19
var assign = require('Object.assign');
@@ -57,6 +58,10 @@ function isInternalComponentType(type) {
58
function instantiateReactComponent(node, parentCompositeType) {
59
var instance;
60
61
+ if (node === null || node === false) {
62
+ node = ReactEmptyComponent.emptyElement;
63
+ }
64
+
65
if (typeof node === 'object') {
66
var element = node;
67
if (__DEV__) {