add Portal support to React.Children calls (#11378)
Matteo Vesprini-Heidrich committed
Oct 31, 2017 at 10:59 UTC
0752a63f59168b56b14ec45220bad97b39222604
2 files changed
+30
-2
packages/react/src/ReactChildren.js
+5
-2
@@ -25,7 +25,9 @@ var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec.
25
var REACT_ELEMENT_TYPE =
26
(typeof Symbol === 'function' && Symbol.for && Symbol.for('react.element')) ||
27
0xeac7;
28
-
28
+const REACT_PORTAL_TYPE =
29
+ (typeof Symbol === 'function' && Symbol.for && Symbol.for('react.portal')) ||
30
+ 0xeaca;
31
var SEPARATOR = '.';
32
var SUBSEPARATOR = ':';
33
@@ -125,7 +127,8 @@ function traverseAllChildrenImpl(
127
type === 'number' ||
128
// The following is inlined from ReactElement. This means we can optimize
129
// some checks. React Fiber also inlines this logic for similar purposes.
128
- (type === 'object' && children.$$typeof === REACT_ELEMENT_TYPE)
130
+ (type === 'object' && children.$$typeof === REACT_ELEMENT_TYPE) ||
131
+ (type === 'object' && children.$$typeof === REACT_PORTAL_TYPE)
132
) {
133
callback(
134
traverseContext,
packages/react/src/__tests__/ReactChildren-test.js
+25
@@ -48,6 +48,31 @@ describe('ReactChildren', () => {
48
expect(mappedChildren[0]).toEqual(<span key=".$simple" />);
49
});
50
51
+ it('should support Portal components', () => {
52
+ const context = {};
53
+ const callback = jasmine.createSpy().and.callFake(function(kid, index) {
54
+ expect(this).toBe(context);
55
+ return kid;
56
+ });
57
+ const ReactDOM = require('react-dom');
58
+ const portalContainer = document.createElement('div');
59
+
60
+ const simpleChild = <span key="simple" />;
61
+ const portal = ReactDOM.createPortal(simpleChild, portalContainer);
62
+ const instance = <div>{portal}</div>;
63
+
64
+ React.Children.forEach(instance.props.children, callback, context);
65
+ expect(callback).toHaveBeenCalledWith(portal, 0);
66
+ callback.calls.reset();
67
+ const mappedChildren = React.Children.map(
68
+ instance.props.children,
69
+ callback,
70
+ context,
71
+ );
72
+ expect(callback).toHaveBeenCalledWith(portal, 0);
73
+ expect(mappedChildren[0]).toEqual(portal);
74
+ });
75
+
76
it('should treat single arrayless child as being in array', () => {
77
var context = {};
78
var callback = jasmine.createSpy().and.callFake(function(kid, index) {