Skip to content

Commit 2c7c783

Browse files
authored
Merge pull request #8936 from acdlite/removemapsaschildren
Remove experimental support for maps as children
2 parents a2c49f4 + 14962f8 commit 2c7c783

File tree

8 files changed

+65
-163
lines changed

8 files changed

+65
-163
lines changed

scripts/fiber/tests-failing.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,5 @@ src/renderers/shared/hooks/__tests__/ReactHostOperationHistoryHook-test.js
4747
src/renderers/shared/shared/__tests__/ReactComponentLifeCycle-test.js
4848
* should carry through each of the phases of setup
4949

50-
src/renderers/shared/shared/__tests__/ReactMultiChildText-test.js
51-
* should reorder keyed text nodes
52-
5350
src/renderers/shared/shared/__tests__/refs-test.js
5451
* Should increase refs with an increase in divs

scripts/fiber/tests-passing-except-dev.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,5 @@ src/renderers/shared/shared/__tests__/ReactCompositeComponent-test.js
111111
* should warn about `setState` in getChildContext
112112
* should disallow nested render calls
113113

114-
src/renderers/shared/shared/__tests__/ReactMultiChild-test.js
115-
* should warn for using maps as children with owner info
116-
117114
src/renderers/shared/shared/__tests__/ReactStatelessComponent-test.js
118115
* should warn for childContextTypes on a functional component

scripts/fiber/tests-passing.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ src/isomorphic/children/__tests__/ReactChildren-test.js
124124
* should retain key across two mappings
125125
* should be called for each child in an iterable without keys
126126
* should be called for each child in an iterable with keys
127-
* should use keys from entry iterables
128127
* should not enumerate enumerable numbers (#4776)
129128
* should allow extension of native prototypes
130129
* should pass key to returned component
@@ -1513,6 +1512,7 @@ src/renderers/shared/shared/__tests__/ReactMultiChild-test.js
15131512
* should replace children with different keys
15141513
* should warn for duplicated array keys with component stack info
15151514
* should warn for duplicated iterable keys with component stack info
1515+
* should warn for using maps as children with owner info
15161516
* should reorder bailed-out children
15171517
* prepares new children before unmounting old
15181518

src/isomorphic/children/__tests__/ReactChildren-test.js

Lines changed: 1 addition & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ describe('ReactChildren', () => {
105105
expect(callback).toHaveBeenCalledWith(one, 1);
106106
expect(callback).toHaveBeenCalledWith(two, 2);
107107
expect(callback).toHaveBeenCalledWith(three, 3);
108-
expect(callback).toHaveBeenCalledWith(four, 4);
108+
expect(callback).toHaveBeenCalledWith(four, 4);
109109
callback.calls.reset();
110110
}
111111

@@ -365,68 +365,6 @@ describe('ReactChildren', () => {
365365
]);
366366
});
367367

368-
it('should use keys from entry iterables', () => {
369-
spyOn(console, 'error');
370-
371-
var threeDivEntryIterable = {
372-
'@@iterator': function() {
373-
var i = 0;
374-
return {
375-
next: function() {
376-
if (i++ < 3) {
377-
return {value: ['#' + i, <div />], done: false};
378-
} else {
379-
return {value: undefined, done: true};
380-
}
381-
},
382-
};
383-
},
384-
};
385-
threeDivEntryIterable.entries = threeDivEntryIterable['@@iterator'];
386-
387-
var context = {};
388-
var callback =
389-
jasmine.createSpy().and.callFake(function(kid) {
390-
expect(this).toBe(context);
391-
return kid;
392-
});
393-
394-
var instance = (
395-
<div>
396-
{threeDivEntryIterable}
397-
</div>
398-
);
399-
400-
function assertCalls() {
401-
expect(callback.calls.count()).toBe(3);
402-
// TODO: why
403-
expect(callback).toHaveBeenCalledWith(<div />, 0);
404-
expect(callback).toHaveBeenCalledWith(<div />, 1);
405-
expect(callback).toHaveBeenCalledWith(<div />, 2);
406-
407-
callback.calls.reset();
408-
}
409-
410-
React.Children.forEach(instance.props.children, callback, context);
411-
assertCalls();
412-
expectDev(console.error.calls.count()).toBe(1);
413-
expectDev(console.error.calls.argsFor(0)[0]).toContain(
414-
'Warning: Using Maps as children is not yet fully supported. It is an ' +
415-
'experimental feature that might be removed. Convert it to a sequence ' +
416-
'/ iterable of keyed ReactElements instead.'
417-
);
418-
console.error.calls.reset();
419-
420-
var mappedChildren = React.Children.map(instance.props.children, callback, context);
421-
assertCalls();
422-
expect(mappedChildren).toEqual([
423-
<div key=".$#1:0" />,
424-
<div key=".$#2:0" />,
425-
<div key=".$#3:0" />,
426-
]);
427-
expectDev(console.error.calls.count()).toBe(0);
428-
});
429-
430368
it('should not enumerate enumerable numbers (#4776)', () => {
431369
/*eslint-disable no-extend-native */
432370
Number.prototype['@@iterator'] = function() {

src/renderers/shared/fiber/ReactChildFiber.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ if (__DEV__) {
4242
var { getCurrentFiberStackAddendum } = require('ReactDebugCurrentFiber');
4343
var { getComponentName } = require('ReactFiberTreeReflection');
4444
var warning = require('warning');
45+
var didWarnAboutMaps = false;
4546
}
4647

4748
const {
@@ -811,6 +812,29 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
811812
);
812813

813814
if (__DEV__) {
815+
// Warn about using Maps as children
816+
if (typeof newChildrenIterable.entries === 'function') {
817+
const possibleMap = (newChildrenIterable : any);
818+
if (possibleMap.entries === iteratorFn) {
819+
let mapsAsChildrenAddendum = '';
820+
const owner = ReactCurrentOwner.owner || returnFiber._debugOwner;
821+
if (owner && typeof owner.tag === 'number') {
822+
const mapsAsChildrenOwnerName = getComponentName((owner : any));
823+
if (mapsAsChildrenOwnerName) {
824+
mapsAsChildrenAddendum = '\n\nCheck the render method of `' + mapsAsChildrenOwnerName + '`.';
825+
}
826+
}
827+
warning(
828+
didWarnAboutMaps,
829+
'Using Maps as children is unsupported and will likely yield ' +
830+
'unexpected results. Convert it to a sequence/iterable of keyed ' +
831+
'ReactElements instead.%s',
832+
mapsAsChildrenAddendum
833+
);
834+
didWarnAboutMaps = true;
835+
}
836+
}
837+
814838
// First, validate keys.
815839
// We'll get a different iterator later for the main pass.
816840
const newChildren = iteratorFn.call(newChildrenIterable);

src/renderers/shared/shared/__tests__/ReactMultiChild-test.js

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -261,28 +261,25 @@ describe('ReactMultiChild', () => {
261261
' in Parent (at **)'
262262
);
263263
});
264+
});
264265

265-
it('should warn for using maps as children with owner info', () => {
266-
spyOn(console, 'error');
267-
268-
class Parent extends React.Component {
269-
render() {
270-
return (
271-
<div>{new Map([['foo', 0], ['bar', 1]])}</div>
272-
);
273-
}
266+
it('should warn for using maps as children with owner info', () => {
267+
spyOn(console, 'error');
268+
class Parent extends React.Component {
269+
render() {
270+
return (
271+
<div>{new Map([['foo', 0], ['bar', 1]])}</div>
272+
);
274273
}
275-
276-
var container = document.createElement('div');
277-
ReactDOM.render(<Parent />, container);
278-
279-
expectDev(console.error.calls.count()).toBe(1);
280-
expectDev(console.error.calls.argsFor(0)[0]).toBe(
281-
'Warning: Using Maps as children is not yet fully supported. It is an ' +
282-
'experimental feature that might be removed. Convert it to a sequence ' +
283-
'/ iterable of keyed ReactElements instead.\n\nCheck the render method of `Parent`.'
284-
);
285-
});
274+
}
275+
var container = document.createElement('div');
276+
ReactDOM.render(<Parent />, container);
277+
expectDev(console.error.calls.count()).toBe(1);
278+
expectDev(console.error.calls.argsFor(0)[0]).toBe(
279+
'Warning: Using Maps as children is unsupported and will likely yield ' +
280+
'unexpected results. Convert it to a sequence/iterable of keyed ' +
281+
'ReactElements instead.\n\nCheck the render method of `Parent`.'
282+
);
286283
});
287284

288285
it('should reorder bailed-out children', () => {

src/renderers/shared/shared/__tests__/ReactMultiChildText-test.js

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -220,38 +220,4 @@ describe('ReactMultiChildText', () => {
220220
ReactTestUtils.renderIntoDocument(<div><h1>{['A', 'B']}</h1></div>);
221221
}).not.toThrow();
222222
});
223-
224-
it('should reorder keyed text nodes', () => {
225-
spyOn(console, 'error');
226-
227-
var container = document.createElement('div');
228-
ReactDOM.render(
229-
<div>{new Map([['a', 'alpha'], ['b', 'beta']])}</div>,
230-
container
231-
);
232-
233-
var childNodes = container.firstChild.childNodes;
234-
var alpha1 = childNodes[0];
235-
var alpha2 = childNodes[1];
236-
var alpha3 = childNodes[2];
237-
var beta1 = childNodes[3];
238-
var beta2 = childNodes[4];
239-
var beta3 = childNodes[5];
240-
241-
ReactDOM.render(
242-
<div>{new Map([['b', 'beta'], ['a', 'alpha']])}</div>,
243-
container
244-
);
245-
246-
childNodes = container.firstChild.childNodes;
247-
expect(childNodes[0]).toBe(beta1);
248-
expect(childNodes[1]).toBe(beta2);
249-
expect(childNodes[2]).toBe(beta3);
250-
expect(childNodes[3]).toBe(alpha1);
251-
expect(childNodes[4]).toBe(alpha2);
252-
expect(childNodes[5]).toBe(alpha3);
253-
254-
// Using Maps as children gives a single warning
255-
expectDev(console.error.calls.count()).toBe(1);
256-
});
257223
});

src/shared/utils/traverseAllChildren.js

Lines changed: 22 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ var SUBSEPARATOR = ':';
3333
* pattern.
3434
*/
3535

36-
var didWarnAboutMaps = false;
36+
var didWarnAboutMaps = false;
3737

3838
/**
3939
* Generate a key string that identifies a component within a set.
@@ -109,23 +109,10 @@ function traverseAllChildrenImpl(
109109
} else {
110110
var iteratorFn = getIteratorFn(children);
111111
if (iteratorFn) {
112-
var iterator = iteratorFn.call(children);
113-
var step;
114-
if (iteratorFn !== children.entries) {
115-
var ii = 0;
116-
while (!(step = iterator.next()).done) {
117-
child = step.value;
118-
nextName = nextNamePrefix + getComponentKey(child, ii++);
119-
subtreeCount += traverseAllChildrenImpl(
120-
child,
121-
nextName,
122-
callback,
123-
traverseContext
124-
);
125-
}
126-
} else {
127-
if (__DEV__) {
128-
var mapsAsChildrenAddendum = '';
112+
if (__DEV__) {
113+
// Warn about using Maps as children
114+
if (iteratorFn === children.entries) {
115+
let mapsAsChildrenAddendum = '';
129116
if (ReactCurrentOwner.current) {
130117
var mapsAsChildrenOwnerName = ReactCurrentOwner.current.getName();
131118
if (mapsAsChildrenOwnerName) {
@@ -134,31 +121,27 @@ function traverseAllChildrenImpl(
134121
}
135122
warning(
136123
didWarnAboutMaps,
137-
'Using Maps as children is not yet fully supported. It is an ' +
138-
'experimental feature that might be removed. Convert it to a ' +
139-
'sequence / iterable of keyed ReactElements instead.%s',
124+
'Using Maps as children is unsupported and will likely yield ' +
125+
'unexpected results. Convert it to a sequence/iterable of keyed ' +
126+
'ReactElements instead.%s',
140127
mapsAsChildrenAddendum
141128
);
142129
didWarnAboutMaps = true;
143130
}
144-
// Iterator will provide entry [k,v] tuples rather than values.
145-
while (!(step = iterator.next()).done) {
146-
var entry = step.value;
147-
if (entry) {
148-
child = entry[1];
149-
nextName = (
150-
nextNamePrefix +
151-
KeyEscapeUtils.escape(entry[0]) + SUBSEPARATOR +
152-
getComponentKey(child, 0)
153-
);
154-
subtreeCount += traverseAllChildrenImpl(
155-
child,
156-
nextName,
157-
callback,
158-
traverseContext
159-
);
160-
}
161-
}
131+
}
132+
133+
var iterator = iteratorFn.call(children);
134+
var step;
135+
var ii = 0;
136+
while (!(step = iterator.next()).done) {
137+
child = step.value;
138+
nextName = nextNamePrefix + getComponentKey(child, ii++);
139+
subtreeCount += traverseAllChildrenImpl(
140+
child,
141+
nextName,
142+
callback,
143+
traverseContext
144+
);
162145
}
163146
} else if (type === 'object') {
164147
var addendum = '';

0 commit comments

Comments
 (0)