@samitouri / QOS-React-2 / commits / a194e51af0

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__) {