From da48ae0b8330aebb39c710df7340ce2ef902b39e Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Wed, 5 Apr 2017 20:26:58 +0900 Subject: [PATCH 01/21] Remove to use PooledClass for traverseAllChildren --- src/isomorphic/children/ReactChildren.js | 74 +++++------------------- 1 file changed, 13 insertions(+), 61 deletions(-) diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js index 206d9465755..cd77e958dde 100644 --- a/src/isomorphic/children/ReactChildren.js +++ b/src/isomorphic/children/ReactChildren.js @@ -11,40 +11,16 @@ 'use strict'; -var PooledClass = require('PooledClass'); var ReactElement = require('ReactElement'); var emptyFunction = require('fbjs/lib/emptyFunction'); var traverseAllChildren = require('traverseAllChildren'); -var twoArgumentPooler = PooledClass.twoArgumentPooler; -var fourArgumentPooler = PooledClass.fourArgumentPooler; - var userProvidedKeyEscapeRegex = /\/+/g; function escapeUserProvidedKey(text) { return ('' + text).replace(userProvidedKeyEscapeRegex, '$&/'); } -/** - * PooledClass representing the bookkeeping associated with performing a child - * traversal. Allows avoiding binding callbacks. - * - * @constructor ForEachBookKeeping - * @param {!function} forEachFunction Function to perform traversal with. - * @param {?*} forEachContext Context to perform context with. - */ -function ForEachBookKeeping(forEachFunction, forEachContext) { - this.func = forEachFunction; - this.context = forEachContext; - this.count = 0; -} -ForEachBookKeeping.prototype.destructor = function() { - this.func = null; - this.context = null; - this.count = 0; -}; -PooledClass.addPoolingTo(ForEachBookKeeping, twoArgumentPooler); - function forEachSingleChild(bookKeeping, child, name) { var {func, context} = bookKeeping; func.call(context, child, bookKeeping.count++); @@ -66,39 +42,14 @@ function forEachChildren(children, forEachFunc, forEachContext) { if (children == null) { return children; } - var traverseContext = ForEachBookKeeping.getPooled( - forEachFunc, - forEachContext, - ); + var traverseContext = { + func: forEachFunc, + context: forEachContext, + count: 0, + }; traverseAllChildren(children, forEachSingleChild, traverseContext); - ForEachBookKeeping.release(traverseContext); } -/** - * PooledClass representing the bookkeeping associated with performing a child - * mapping. Allows avoiding binding callbacks. - * - * @constructor MapBookKeeping - * @param {!*} mapResult Object containing the ordered map of results. - * @param {!function} mapFunction Function to perform mapping with. - * @param {?*} mapContext Context to perform mapping with. - */ -function MapBookKeeping(mapResult, keyPrefix, mapFunction, mapContext) { - this.result = mapResult; - this.keyPrefix = keyPrefix; - this.func = mapFunction; - this.context = mapContext; - this.count = 0; -} -MapBookKeeping.prototype.destructor = function() { - this.result = null; - this.keyPrefix = null; - this.func = null; - this.context = null; - this.count = 0; -}; -PooledClass.addPoolingTo(MapBookKeeping, fourArgumentPooler); - function mapSingleChildIntoContext(bookKeeping, child, childKey) { var {result, keyPrefix, func, context} = bookKeeping; @@ -132,14 +83,15 @@ function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) { if (prefix != null) { escapedPrefix = escapeUserProvidedKey(prefix) + '/'; } - var traverseContext = MapBookKeeping.getPooled( - array, - escapedPrefix, - func, - context, - ); + var traverseContext = { + result: array, + keyPrefix: escapedPrefix, + func: func, + context: context, + count: 0, + }; + traverseAllChildren(children, mapSingleChildIntoContext, traverseContext); - MapBookKeeping.release(traverseContext); } /** From efb71072129b2a9eff9eb4bc5c914d9c0b1abd0f Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Wed, 12 Apr 2017 18:34:08 +0900 Subject: [PATCH 02/21] move traverseAllChildren into ReactChildren --- src/isomorphic/children/ReactChildren.js | 168 ++++++++++++++++++++++- 1 file changed, 164 insertions(+), 4 deletions(-) diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js index cd77e958dde..5c4786ee434 100644 --- a/src/isomorphic/children/ReactChildren.js +++ b/src/isomorphic/children/ReactChildren.js @@ -14,7 +14,161 @@ var ReactElement = require('ReactElement'); var emptyFunction = require('fbjs/lib/emptyFunction'); -var traverseAllChildren = require('traverseAllChildren'); + +var ReactCurrentOwner = require('react/lib/ReactCurrentOwner'); +var REACT_ELEMENT_TYPE = require('ReactElementSymbol'); + +var getIteratorFn = require('getIteratorFn'); +var invariant = require('fbjs/lib/invariant'); +var KeyEscapeUtils = require('KeyEscapeUtils'); +var warning = require('fbjs/lib/warning'); + +var SEPARATOR = '.'; +var SUBSEPARATOR = ':'; + +/** + * This is inlined from ReactElement since this file is shared between + * isomorphic and renderers. We could extract this to a + * + */ + +/** + * TODO: Test that a single child and an array with one item have the same key + * pattern. + */ + +var didWarnAboutMaps = false; + +/** + * Generate a key string that identifies a component within a set. + * + * @param {*} component A component that could contain a manual key. + * @param {number} index Index that is used if a manual key is not provided. + * @return {string} + */ +function getComponentKey(component, index) { + // Do some typechecking here since we call this blindly. We want to ensure + // that we don't block potential future ES APIs. + if (component && typeof component === 'object' && component.key != null) { + // Explicit key + return KeyEscapeUtils.escape(component.key); + } + // Implicit key determined by the index in the set + return index.toString(36); +} + +function traverseAllChildren( + children, + nameSoFar, + callback, + traverseContext, +) { + var type = typeof children; + + if (type === 'undefined' || type === 'boolean') { + // All of the above are perceived as null. + children = null; + } + + if ( + children === null || + type === 'string' || + type === 'number' || + // The following is inlined from ReactElement. This means we can optimize + // some checks. React Fiber also inlines this logic for similar purposes. + (type === 'object' && children.$$typeof === REACT_ELEMENT_TYPE) + ) { + callback( + traverseContext, + children, + // If it's the only child, treat the name as if it was wrapped in an array + // so that it's consistent if the number of children grows. + nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar, + ); + return 1; + } + + var child; + var nextName; + var subtreeCount = 0; // Count of children found in the current subtree. + var nextNamePrefix = nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR; + + if (Array.isArray(children)) { + for (var i = 0; i < children.length; i++) { + child = children[i]; + nextName = nextNamePrefix + getComponentKey(child, i); + subtreeCount += traverseAllChildren( + child, + nextName, + callback, + traverseContext, + ); + } + } else { + var iteratorFn = getIteratorFn(children); + if (iteratorFn) { + if (__DEV__) { + // Warn about using Maps as children + if (iteratorFn === children.entries) { + let mapsAsChildrenAddendum = ''; + if (ReactCurrentOwner.current) { + var mapsAsChildrenOwnerName = ReactCurrentOwner.current.getName(); + if (mapsAsChildrenOwnerName) { + mapsAsChildrenAddendum = '\n\nCheck the render method of `' + + mapsAsChildrenOwnerName + + '`.'; + } + } + warning( + didWarnAboutMaps, + 'Using Maps as children is unsupported and will likely yield ' + + 'unexpected results. Convert it to a sequence/iterable of keyed ' + + 'ReactElements instead.%s', + mapsAsChildrenAddendum, + ); + didWarnAboutMaps = true; + } + } + + var iterator = iteratorFn.call(children); + var step; + var ii = 0; + while (!(step = iterator.next()).done) { + child = step.value; + nextName = nextNamePrefix + getComponentKey(child, ii++); + subtreeCount += traverseAllChildren( + child, + nextName, + callback, + traverseContext, + ); + } + } else if (type === 'object') { + var addendum = ''; + if (__DEV__) { + addendum = ' If you meant to render a collection of children, use an array ' + + 'instead.'; + if (ReactCurrentOwner.current) { + var name = ReactCurrentOwner.current.getName(); + if (name) { + addendum += '\n\nCheck the render method of `' + name + '`.'; + } + } + } + var childrenString = '' + children; + invariant( + false, + 'Objects are not valid as a React child (found: %s).%s', + childrenString === '[object Object]' + ? 'object with keys {' + Object.keys(children).join(', ') + '}' + : childrenString, + addendum, + ); + } + } + + return subtreeCount; +} var userProvidedKeyEscapeRegex = /\/+/g; function escapeUserProvidedKey(text) { @@ -47,7 +201,7 @@ function forEachChildren(children, forEachFunc, forEachContext) { context: forEachContext, count: 0, }; - traverseAllChildren(children, forEachSingleChild, traverseContext); + traverseAllChildren(children, '', forEachSingleChild, traverseContext); } function mapSingleChildIntoContext(bookKeeping, child, childKey) { @@ -79,6 +233,9 @@ function mapSingleChildIntoContext(bookKeeping, child, childKey) { } function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) { + if (children == null) { + return; + } var escapedPrefix = ''; if (prefix != null) { escapedPrefix = escapeUserProvidedKey(prefix) + '/'; @@ -91,7 +248,7 @@ function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) { count: 0, }; - traverseAllChildren(children, mapSingleChildIntoContext, traverseContext); + traverseAllChildren(children, '', mapSingleChildIntoContext, traverseContext); } /** @@ -130,7 +287,10 @@ function forEachSingleChildDummy(traverseContext, child, name) { * @return {number} The number of children. */ function countChildren(children, context) { - return traverseAllChildren(children, forEachSingleChildDummy, null); + if (children == null) { + return 0; + } + return traverseAllChildren(children, '', forEachSingleChildDummy, null); } /** From d5b4b570523a463ba36c854a3be9a5964681458c Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Fri, 14 Apr 2017 17:06:04 +0900 Subject: [PATCH 03/21] Use mapChildren to forEach and toArray --- src/isomorphic/children/ReactChildren.js | 86 ++++++++++-------------- 1 file changed, 36 insertions(+), 50 deletions(-) diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js index 5c4786ee434..ed1a34bcc23 100644 --- a/src/isomorphic/children/ReactChildren.js +++ b/src/isomorphic/children/ReactChildren.js @@ -175,35 +175,6 @@ function escapeUserProvidedKey(text) { return ('' + text).replace(userProvidedKeyEscapeRegex, '$&/'); } -function forEachSingleChild(bookKeeping, child, name) { - var {func, context} = bookKeeping; - func.call(context, child, bookKeeping.count++); -} - -/** - * Iterates through children that are typically specified as `props.children`. - * - * See https://facebook.github.io/react/docs/react-api.html#react.children.foreach - * - * The provided forEachFunc(child, index) will be called for each - * leaf child. - * - * @param {?*} children Children tree container. - * @param {function(*, int)} forEachFunc - * @param {*} forEachContext Context for forEachContext. - */ -function forEachChildren(children, forEachFunc, forEachContext) { - if (children == null) { - return children; - } - var traverseContext = { - func: forEachFunc, - context: forEachContext, - count: 0, - }; - traverseAllChildren(children, '', forEachSingleChild, traverseContext); -} - function mapSingleChildIntoContext(bookKeeping, child, childKey) { var {result, keyPrefix, func, context} = bookKeeping; @@ -269,12 +240,44 @@ function mapChildren(children, func, context) { return children; } var result = []; - mapIntoWithKeyPrefixInternal(children, result, null, func, context); + var traverseContext = { + result: result, + keyPrefix: '', + func: func, + context: context, + count: 0, + }; + traverseAllChildren(children, '', mapSingleChildIntoContext, traverseContext); return result; } -function forEachSingleChildDummy(traverseContext, child, name) { - return null; +/** + * Iterates through children that are typically specified as `props.children`. + * + * See https://facebook.github.io/react/docs/react-api.html#react.children.foreach + * + * The provided forEachFunc(child, index) will be called for each + * leaf child. + * + * @param {?*} children Children tree container. + * @param {function(*, int)} forEachFunc + * @param {*} forEachContext Context for forEachContext. + */ +function forEachChildren(children, forEachFunc, forEachContext) { + mapChildren(children, forEachFunc, forEachContext); +} + +/** + * Flatten a children object (typically specified as `props.children`) and + * return an array with appropriately re-keyed children. + * + * See https://facebook.github.io/react/docs/react-api.html#react.children.toarray + */ +function toArray(children) { + if (children == null) { + return []; + } + return mapChildren(children, emptyFunction.thatReturnsArgument, null); } /** @@ -290,24 +293,7 @@ function countChildren(children, context) { if (children == null) { return 0; } - return traverseAllChildren(children, '', forEachSingleChildDummy, null); -} - -/** - * Flatten a children object (typically specified as `props.children`) and - * return an array with appropriately re-keyed children. - * - * See https://facebook.github.io/react/docs/react-api.html#react.children.toarray - */ -function toArray(children) { - var result = []; - mapIntoWithKeyPrefixInternal( - children, - result, - null, - emptyFunction.thatReturnsArgument, - ); - return result; + return traverseAllChildren(children, '', emptyFunction.thatReturns, null); } var ReactChildren = { From 437120d40d075d70f3fdf3254079c626cacce0e2 Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Mon, 17 Apr 2017 17:17:34 +0900 Subject: [PATCH 04/21] Remove React.Children.mapIntoWithKeyPrefixInternal --- src/isomorphic/children/ReactChildren.js | 40 ++++++++---------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js index ed1a34bcc23..bbaf4a3b4a5 100644 --- a/src/isomorphic/children/ReactChildren.js +++ b/src/isomorphic/children/ReactChildren.js @@ -179,14 +179,20 @@ function mapSingleChildIntoContext(bookKeeping, child, childKey) { var {result, keyPrefix, func, context} = bookKeeping; var mappedChild = func.call(context, child, bookKeeping.count++); + if (mappedChild == null) { + return; + } + if (Array.isArray(mappedChild)) { - mapIntoWithKeyPrefixInternal( - mappedChild, - result, - childKey, - emptyFunction.thatReturnsArgument, - ); - } else if (mappedChild != null) { + var traverseContext = { + result: result, + keyPrefix: childKey != null ? escapeUserProvidedKey(childKey) + '/' : '', + func: emptyFunction.thatReturnsArgument, + context: null, + count: 0, + }; + traverseAllChildren(mappedChild, '', mapSingleChildIntoContext, traverseContext); + } else { if (ReactElement.isValidElement(mappedChild)) { mappedChild = ReactElement.cloneAndReplaceKey( mappedChild, @@ -203,25 +209,6 @@ function mapSingleChildIntoContext(bookKeeping, child, childKey) { } } -function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) { - if (children == null) { - return; - } - var escapedPrefix = ''; - if (prefix != null) { - escapedPrefix = escapeUserProvidedKey(prefix) + '/'; - } - var traverseContext = { - result: array, - keyPrefix: escapedPrefix, - func: func, - context: context, - count: 0, - }; - - traverseAllChildren(children, '', mapSingleChildIntoContext, traverseContext); -} - /** * Maps children that are typically specified as `props.children`. * @@ -299,7 +286,6 @@ function countChildren(children, context) { var ReactChildren = { forEach: forEachChildren, map: mapChildren, - mapIntoWithKeyPrefixInternal: mapIntoWithKeyPrefixInternal, count: countChildren, toArray: toArray, }; From a2bcddc44fe7fcbb4876c77c87cc36474105cc73 Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Mon, 17 Apr 2017 17:19:05 +0900 Subject: [PATCH 05/21] Run prettier --- src/isomorphic/children/ReactChildren.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js index bbaf4a3b4a5..fdf4a389e1b 100644 --- a/src/isomorphic/children/ReactChildren.js +++ b/src/isomorphic/children/ReactChildren.js @@ -57,12 +57,7 @@ function getComponentKey(component, index) { return index.toString(36); } -function traverseAllChildren( - children, - nameSoFar, - callback, - traverseContext, -) { +function traverseAllChildren(children, nameSoFar, callback, traverseContext) { var type = typeof children; if (type === 'undefined' || type === 'boolean') { @@ -191,7 +186,12 @@ function mapSingleChildIntoContext(bookKeeping, child, childKey) { context: null, count: 0, }; - traverseAllChildren(mappedChild, '', mapSingleChildIntoContext, traverseContext); + traverseAllChildren( + mappedChild, + '', + mapSingleChildIntoContext, + traverseContext, + ); } else { if (ReactElement.isValidElement(mappedChild)) { mappedChild = ReactElement.cloneAndReplaceKey( From e6060f61ac6ffcc65ba51b02329086e5b4bd5060 Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Mon, 17 Apr 2017 18:09:46 +0900 Subject: [PATCH 06/21] Remove unnecessary arguments --- src/isomorphic/children/ReactChildren.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js index fdf4a389e1b..244207516d0 100644 --- a/src/isomorphic/children/ReactChildren.js +++ b/src/isomorphic/children/ReactChildren.js @@ -264,7 +264,7 @@ function toArray(children) { if (children == null) { return []; } - return mapChildren(children, emptyFunction.thatReturnsArgument, null); + return mapChildren(children, emptyFunction.thatReturnsArgument); } /** @@ -280,7 +280,7 @@ function countChildren(children, context) { if (children == null) { return 0; } - return traverseAllChildren(children, '', emptyFunction.thatReturns, null); + return traverseAllChildren(children, '', emptyFunction.thatReturns); } var ReactChildren = { From ed041b4caca2d9f4a0213aa2bb05c48821be02bf Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Tue, 18 Apr 2017 10:23:57 +0900 Subject: [PATCH 07/21] Remove an unused argument from ReactChildren.count --- src/isomorphic/children/ReactChildren.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js index 244207516d0..1ccbf8e18af 100644 --- a/src/isomorphic/children/ReactChildren.js +++ b/src/isomorphic/children/ReactChildren.js @@ -276,7 +276,7 @@ function toArray(children) { * @param {?*} children Children tree container. * @return {number} The number of children. */ -function countChildren(children, context) { +function countChildren(children) { if (children == null) { return 0; } From 1ead8825f68bd7404e7426affc2942f7fadb6d1a Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Thu, 20 Apr 2017 18:40:51 +0900 Subject: [PATCH 08/21] Test for a single child and an array with one item --- src/isomorphic/children/ReactChildren.js | 5 ----- src/isomorphic/children/__tests__/ReactChildren-test.js | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js index 1ccbf8e18af..a7f95134292 100644 --- a/src/isomorphic/children/ReactChildren.js +++ b/src/isomorphic/children/ReactChildren.js @@ -32,11 +32,6 @@ var SUBSEPARATOR = ':'; * */ -/** - * TODO: Test that a single child and an array with one item have the same key - * pattern. - */ - var didWarnAboutMaps = false; /** diff --git a/src/isomorphic/children/__tests__/ReactChildren-test.js b/src/isomorphic/children/__tests__/ReactChildren-test.js index 9d97007cd17..6a754be0a2e 100644 --- a/src/isomorphic/children/__tests__/ReactChildren-test.js +++ b/src/isomorphic/children/__tests__/ReactChildren-test.js @@ -60,7 +60,7 @@ describe('ReactChildren', () => { return kid; }); - var simpleKid = ; + var simpleKid = ; var instance =
{simpleKid}
; React.Children.forEach(instance.props.children, callback, context); expect(callback).toHaveBeenCalledWith(simpleKid, 0); @@ -71,7 +71,7 @@ describe('ReactChildren', () => { context, ); expect(callback).toHaveBeenCalledWith(simpleKid, 0); - expect(mappedChildren[0]).toEqual(); + expect(mappedChildren[0]).toEqual(); }); it('should treat single child in array as expected', () => { From ab49e3acc1b53a531fdcd218ede80f5addc9b189 Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Fri, 21 Apr 2017 09:58:39 +0900 Subject: [PATCH 09/21] Add component stack to invalid-object-child error (cherry-pick #9415) --- src/isomorphic/children/ReactChildren.js | 27 ++++++++---------------- 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js index a7f95134292..7cd8356b397 100644 --- a/src/isomorphic/children/ReactChildren.js +++ b/src/isomorphic/children/ReactChildren.js @@ -15,7 +15,6 @@ var ReactElement = require('ReactElement'); var emptyFunction = require('fbjs/lib/emptyFunction'); -var ReactCurrentOwner = require('react/lib/ReactCurrentOwner'); var REACT_ELEMENT_TYPE = require('ReactElementSymbol'); var getIteratorFn = require('getIteratorFn'); @@ -23,6 +22,12 @@ var invariant = require('fbjs/lib/invariant'); var KeyEscapeUtils = require('KeyEscapeUtils'); var warning = require('fbjs/lib/warning'); +if (__DEV__) { + var { + getCurrentStackAddendum, + } = require('ReactComponentTreeHook'); +} + var SEPARATOR = '.'; var SUBSEPARATOR = ':'; @@ -100,21 +105,12 @@ function traverseAllChildren(children, nameSoFar, callback, traverseContext) { if (__DEV__) { // Warn about using Maps as children if (iteratorFn === children.entries) { - let mapsAsChildrenAddendum = ''; - if (ReactCurrentOwner.current) { - var mapsAsChildrenOwnerName = ReactCurrentOwner.current.getName(); - if (mapsAsChildrenOwnerName) { - mapsAsChildrenAddendum = '\n\nCheck the render method of `' + - mapsAsChildrenOwnerName + - '`.'; - } - } warning( didWarnAboutMaps, 'Using Maps as children is unsupported and will likely yield ' + 'unexpected results. Convert it to a sequence/iterable of keyed ' + 'ReactElements instead.%s', - mapsAsChildrenAddendum, + getCurrentStackAddendum(), ); didWarnAboutMaps = true; } @@ -137,13 +133,8 @@ function traverseAllChildren(children, nameSoFar, callback, traverseContext) { var addendum = ''; if (__DEV__) { addendum = ' If you meant to render a collection of children, use an array ' + - 'instead.'; - if (ReactCurrentOwner.current) { - var name = ReactCurrentOwner.current.getName(); - if (name) { - addendum += '\n\nCheck the render method of `' + name + '`.'; - } - } + 'instead.' + + getCurrentStackAddendum(); } var childrenString = '' + children; invariant( From 2e982b9d7617443237b3d29fc88cdb113f6b4ab3 Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Fri, 21 Apr 2017 10:04:16 +0900 Subject: [PATCH 10/21] Add test for single child witout key --- .../children/__tests__/ReactChildren-test.js | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/isomorphic/children/__tests__/ReactChildren-test.js b/src/isomorphic/children/__tests__/ReactChildren-test.js index 6a754be0a2e..0f9eb06726e 100644 --- a/src/isomorphic/children/__tests__/ReactChildren-test.js +++ b/src/isomorphic/children/__tests__/ReactChildren-test.js @@ -28,6 +28,27 @@ describe('ReactChildren', () => { ReactTestUtils = require('react-dom/test-utils'); }); + it('should support single child without key', () => { + var context = {}; + var callback = jasmine.createSpy().and.callFake(function(kid, index) { + expect(this).toBe(context); + return kid; + }); + + var simpleKid = ; + var instance =
{simpleKid}
; + React.Children.forEach(instance.props.children, callback, context); + expect(callback).toHaveBeenCalledWith(simpleKid, 0); + callback.calls.reset(); + var mappedChildren = React.Children.map( + instance.props.children, + callback, + context, + ); + expect(callback).toHaveBeenCalledWith(simpleKid, 0); + expect(mappedChildren[0]).toEqual(); + }); + it('should support identity for simple', () => { var context = {}; var callback = jasmine.createSpy().and.callFake(function(kid, index) { From 892dd52f0f8ca33fcd739081415ac6bbef756cbd Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Wed, 26 Apr 2017 12:27:54 +0900 Subject: [PATCH 11/21] Improve component type check in getComponentKey (cherry-pick #9464) --- src/isomorphic/children/ReactChildren.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js index 7cd8356b397..6eba0d7ee9e 100644 --- a/src/isomorphic/children/ReactChildren.js +++ b/src/isomorphic/children/ReactChildren.js @@ -49,7 +49,9 @@ var didWarnAboutMaps = false; function getComponentKey(component, index) { // Do some typechecking here since we call this blindly. We want to ensure // that we don't block potential future ES APIs. - if (component && typeof component === 'object' && component.key != null) { + if ( + typeof component === 'object' && component !== null && component.key != null + ) { // Explicit key return KeyEscapeUtils.escape(component.key); } From 1e5ab7c59c1a4ddab877f5a00696a37dac9f9f3f Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Mon, 8 May 2017 14:43:33 +0900 Subject: [PATCH 12/21] Add Flow types --- src/isomorphic/children/ReactChildren.js | 50 ++++++++++++++---------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js index 6eba0d7ee9e..e89d986a9ae 100644 --- a/src/isomorphic/children/ReactChildren.js +++ b/src/isomorphic/children/ReactChildren.js @@ -7,6 +7,7 @@ * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule ReactChildren + * @flow */ 'use strict'; @@ -40,20 +41,20 @@ var SUBSEPARATOR = ':'; var didWarnAboutMaps = false; /** - * Generate a key string that identifies a component within a set. + * Generate a key string that identifies a ReactElement within a set. * - * @param {*} component A component that could contain a manual key. + * @param {*} element A ReactElement that could contain a manual key. * @param {number} index Index that is used if a manual key is not provided. * @return {string} */ -function getComponentKey(component, index) { +function getReactElementKey(element: ?ReactElement, index) { // Do some typechecking here since we call this blindly. We want to ensure // that we don't block potential future ES APIs. if ( - typeof component === 'object' && component !== null && component.key != null + typeof element === 'object' && element !== null && element.key != null ) { // Explicit key - return KeyEscapeUtils.escape(component.key); + return KeyEscapeUtils.escape(element.key); } // Implicit key determined by the index in the set return index.toString(36); @@ -73,14 +74,14 @@ function traverseAllChildren(children, nameSoFar, callback, traverseContext) { type === 'number' || // The following is inlined from ReactElement. This means we can optimize // some checks. React Fiber also inlines this logic for similar purposes. - (type === 'object' && children.$$typeof === REACT_ELEMENT_TYPE) + (type === 'object' && (children: ReactElement).$$typeof === REACT_ELEMENT_TYPE) ) { callback( traverseContext, children, // If it's the only child, treat the name as if it was wrapped in an array // so that it's consistent if the number of children grows. - nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar, + nameSoFar === '' ? SEPARATOR + getReactElementKey(children, 0) : nameSoFar, ); return 1; } @@ -93,7 +94,7 @@ function traverseAllChildren(children, nameSoFar, callback, traverseContext) { if (Array.isArray(children)) { for (var i = 0; i < children.length; i++) { child = children[i]; - nextName = nextNamePrefix + getComponentKey(child, i); + nextName = nextNamePrefix + getReactElementKey(child, i); subtreeCount += traverseAllChildren( child, nextName, @@ -106,7 +107,7 @@ function traverseAllChildren(children, nameSoFar, callback, traverseContext) { if (iteratorFn) { if (__DEV__) { // Warn about using Maps as children - if (iteratorFn === children.entries) { + if (children != null && iteratorFn === children.entries) { warning( didWarnAboutMaps, 'Using Maps as children is unsupported and will likely yield ' + @@ -121,9 +122,9 @@ function traverseAllChildren(children, nameSoFar, callback, traverseContext) { var iterator = iteratorFn.call(children); var step; var ii = 0; - while (!(step = iterator.next()).done) { - child = step.value; - nextName = nextNamePrefix + getComponentKey(child, ii++); + while (iterator && !(step = iterator.next()).done) { + child = step != null && step.value; + nextName = nextNamePrefix + getReactElementKey(child, ii++); subtreeCount += traverseAllChildren( child, nextName, @@ -138,12 +139,12 @@ function traverseAllChildren(children, nameSoFar, callback, traverseContext) { 'instead.' + getCurrentStackAddendum(); } - var childrenString = '' + children; + var childrenString = '' + (children: ReactElement); invariant( false, 'Objects are not valid as a React child (found: %s).%s', childrenString === '[object Object]' - ? 'object with keys {' + Object.keys(children).join(', ') + '}' + ? 'object with keys {' + Object.keys((children: ReactElement)).join(', ') + '}' : childrenString, addendum, ); @@ -154,7 +155,7 @@ function traverseAllChildren(children, nameSoFar, callback, traverseContext) { } var userProvidedKeyEscapeRegex = /\/+/g; -function escapeUserProvidedKey(text) { +function escapeUserProvidedKey(text: string) { return ('' + text).replace(userProvidedKeyEscapeRegex, '$&/'); } @@ -188,7 +189,7 @@ function mapSingleChildIntoContext(bookKeeping, child, childKey) { // traverseAllChildren used to do for objects as children keyPrefix + (mappedChild.key && (!child || child.key !== mappedChild.key) - ? escapeUserProvidedKey(mappedChild.key) + '/' + ? escapeUserProvidedKey((mappedChild: ReactElement).key) + '/' : '') + childKey, ); @@ -210,7 +211,7 @@ function mapSingleChildIntoContext(bookKeeping, child, childKey) { * @param {*} context Context for mapFunction. * @return {object} Object containing the ordered map of results. */ -function mapChildren(children, func, context) { +function mapChildren(children: mixed, func: () => mixed, context?: Object): ?mixed[] { if (children == null) { return children; } @@ -238,7 +239,7 @@ function mapChildren(children, func, context) { * @param {function(*, int)} forEachFunc * @param {*} forEachContext Context for forEachContext. */ -function forEachChildren(children, forEachFunc, forEachContext) { +function forEachChildren(children: mixed, forEachFunc: () => mixed, forEachContext?: Object): void { mapChildren(children, forEachFunc, forEachContext); } @@ -248,7 +249,7 @@ function forEachChildren(children, forEachFunc, forEachContext) { * * See https://facebook.github.io/react/docs/react-api.html#react.children.toarray */ -function toArray(children) { +function toArray(children: mixed): ?mixed[] { if (children == null) { return []; } @@ -264,11 +265,18 @@ function toArray(children) { * @param {?*} children Children tree container. * @return {number} The number of children. */ -function countChildren(children) { +function countChildren(children: mixed): number { if (children == null) { return 0; } - return traverseAllChildren(children, '', emptyFunction.thatReturns); + var traverseContext = { + result: [], + keyPrefix: '', + func: emptyFunction.thatReturns, + context: {}, + count: 0, + }; + return traverseAllChildren(children, '', emptyFunction.thatReturns, traverseContext); } var ReactChildren = { From a6cdc05d2897113379068d89eddc3e19bd21657d Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Mon, 8 May 2017 17:37:10 +0900 Subject: [PATCH 13/21] Type for getReactElementKey --- src/isomorphic/children/ReactChildren.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js index e89d986a9ae..06adad83804 100644 --- a/src/isomorphic/children/ReactChildren.js +++ b/src/isomorphic/children/ReactChildren.js @@ -47,7 +47,7 @@ var didWarnAboutMaps = false; * @param {number} index Index that is used if a manual key is not provided. * @return {string} */ -function getReactElementKey(element: ?ReactElement, index) { +function getReactElementKey(element, index) { // Do some typechecking here since we call this blindly. We want to ensure // that we don't block potential future ES APIs. if ( @@ -81,7 +81,7 @@ function traverseAllChildren(children, nameSoFar, callback, traverseContext) { children, // If it's the only child, treat the name as if it was wrapped in an array // so that it's consistent if the number of children grows. - nameSoFar === '' ? SEPARATOR + getReactElementKey(children, 0) : nameSoFar, + nameSoFar === '' ? SEPARATOR + getReactElementKey((children: ReactElement), 0) : nameSoFar, ); return 1; } @@ -93,7 +93,7 @@ function traverseAllChildren(children, nameSoFar, callback, traverseContext) { if (Array.isArray(children)) { for (var i = 0; i < children.length; i++) { - child = children[i]; + child = (children[i]: ReactElement); nextName = nextNamePrefix + getReactElementKey(child, i); subtreeCount += traverseAllChildren( child, @@ -123,7 +123,7 @@ function traverseAllChildren(children, nameSoFar, callback, traverseContext) { var step; var ii = 0; while (iterator && !(step = iterator.next()).done) { - child = step != null && step.value; + child = step != null && (step.value: ReactElement); nextName = nextNamePrefix + getReactElementKey(child, ii++); subtreeCount += traverseAllChildren( child, From 8a306690ca94a155a18237e928b45fd1775e4414 Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Mon, 8 May 2017 17:48:55 +0900 Subject: [PATCH 14/21] Remove comments for types --- src/isomorphic/children/ReactChildren.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js index 06adad83804..34ac4898d21 100644 --- a/src/isomorphic/children/ReactChildren.js +++ b/src/isomorphic/children/ReactChildren.js @@ -42,10 +42,6 @@ var didWarnAboutMaps = false; /** * Generate a key string that identifies a ReactElement within a set. - * - * @param {*} element A ReactElement that could contain a manual key. - * @param {number} index Index that is used if a manual key is not provided. - * @return {string} */ function getReactElementKey(element, index) { // Do some typechecking here since we call this blindly. We want to ensure @@ -205,11 +201,6 @@ function mapSingleChildIntoContext(bookKeeping, child, childKey) { * * The provided mapFunction(child, key, index) will be called for each * leaf child. - * - * @param {?*} children Children tree container. - * @param {function(*, int)} func The map function. - * @param {*} context Context for mapFunction. - * @return {object} Object containing the ordered map of results. */ function mapChildren(children: mixed, func: () => mixed, context?: Object): ?mixed[] { if (children == null) { @@ -234,10 +225,6 @@ function mapChildren(children: mixed, func: () => mixed, context?: Object): ?mix * * The provided forEachFunc(child, index) will be called for each * leaf child. - * - * @param {?*} children Children tree container. - * @param {function(*, int)} forEachFunc - * @param {*} forEachContext Context for forEachContext. */ function forEachChildren(children: mixed, forEachFunc: () => mixed, forEachContext?: Object): void { mapChildren(children, forEachFunc, forEachContext); @@ -261,9 +248,6 @@ function toArray(children: mixed): ?mixed[] { * `props.children`. * * See https://facebook.github.io/react/docs/react-api.html#react.children.count - * - * @param {?*} children Children tree container. - * @return {number} The number of children. */ function countChildren(children: mixed): number { if (children == null) { From 8879aef802f0dd00b2942de2e77b295e0cd96cb7 Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Mon, 8 May 2017 18:22:25 +0900 Subject: [PATCH 15/21] Run prettier --- src/isomorphic/children/ReactChildren.js | 43 ++++++++++++++++-------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js index 34ac4898d21..9228f17a8e0 100644 --- a/src/isomorphic/children/ReactChildren.js +++ b/src/isomorphic/children/ReactChildren.js @@ -24,9 +24,7 @@ var KeyEscapeUtils = require('KeyEscapeUtils'); var warning = require('fbjs/lib/warning'); if (__DEV__) { - var { - getCurrentStackAddendum, - } = require('ReactComponentTreeHook'); + var {getCurrentStackAddendum} = require('ReactComponentTreeHook'); } var SEPARATOR = '.'; @@ -46,9 +44,7 @@ var didWarnAboutMaps = false; function getReactElementKey(element, index) { // Do some typechecking here since we call this blindly. We want to ensure // that we don't block potential future ES APIs. - if ( - typeof element === 'object' && element !== null && element.key != null - ) { + if (typeof element === 'object' && element !== null && element.key != null) { // Explicit key return KeyEscapeUtils.escape(element.key); } @@ -70,14 +66,17 @@ function traverseAllChildren(children, nameSoFar, callback, traverseContext) { type === 'number' || // The following is inlined from ReactElement. This means we can optimize // some checks. React Fiber also inlines this logic for similar purposes. - (type === 'object' && (children: ReactElement).$$typeof === REACT_ELEMENT_TYPE) + (type === 'object' && + (children: ReactElement).$$typeof === REACT_ELEMENT_TYPE) ) { callback( traverseContext, children, // If it's the only child, treat the name as if it was wrapped in an array // so that it's consistent if the number of children grows. - nameSoFar === '' ? SEPARATOR + getReactElementKey((children: ReactElement), 0) : nameSoFar, + nameSoFar === '' + ? SEPARATOR + getReactElementKey((children: ReactElement), 0) + : nameSoFar, ); return 1; } @@ -131,7 +130,8 @@ function traverseAllChildren(children, nameSoFar, callback, traverseContext) { } else if (type === 'object') { var addendum = ''; if (__DEV__) { - addendum = ' If you meant to render a collection of children, use an array ' + + addendum = + ' If you meant to render a collection of children, use an array ' + 'instead.' + getCurrentStackAddendum(); } @@ -140,7 +140,9 @@ function traverseAllChildren(children, nameSoFar, callback, traverseContext) { false, 'Objects are not valid as a React child (found: %s).%s', childrenString === '[object Object]' - ? 'object with keys {' + Object.keys((children: ReactElement)).join(', ') + '}' + ? 'object with keys {' + + Object.keys((children: ReactElement)).join(', ') + + '}' : childrenString, addendum, ); @@ -202,7 +204,11 @@ function mapSingleChildIntoContext(bookKeeping, child, childKey) { * The provided mapFunction(child, key, index) will be called for each * leaf child. */ -function mapChildren(children: mixed, func: () => mixed, context?: Object): ?mixed[] { +function mapChildren( + children: mixed, + func: () => mixed, + context?: Object, +): ?(mixed[]) { if (children == null) { return children; } @@ -226,7 +232,11 @@ function mapChildren(children: mixed, func: () => mixed, context?: Object): ?mix * The provided forEachFunc(child, index) will be called for each * leaf child. */ -function forEachChildren(children: mixed, forEachFunc: () => mixed, forEachContext?: Object): void { +function forEachChildren( + children: mixed, + forEachFunc: () => mixed, + forEachContext?: Object, +): void { mapChildren(children, forEachFunc, forEachContext); } @@ -236,7 +246,7 @@ function forEachChildren(children: mixed, forEachFunc: () => mixed, forEachConte * * See https://facebook.github.io/react/docs/react-api.html#react.children.toarray */ -function toArray(children: mixed): ?mixed[] { +function toArray(children: mixed): ?(mixed[]) { if (children == null) { return []; } @@ -260,7 +270,12 @@ function countChildren(children: mixed): number { context: {}, count: 0, }; - return traverseAllChildren(children, '', emptyFunction.thatReturns, traverseContext); + return traverseAllChildren( + children, + '', + emptyFunction.thatReturns, + traverseContext, + ); } var ReactChildren = { From d57fab82447f210e4f5e7b101875e84da8c739fe Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Tue, 9 May 2017 09:50:33 +0900 Subject: [PATCH 16/21] Do not allocate results with forEach --- src/isomorphic/children/ReactChildren.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js index 9228f17a8e0..780448d0c3f 100644 --- a/src/isomorphic/children/ReactChildren.js +++ b/src/isomorphic/children/ReactChildren.js @@ -224,6 +224,11 @@ function mapChildren( return result; } +function forEachSingleChild(bookKeeping, child, name) { + var {func, context} = bookKeeping; + func.call(context, child, bookKeeping.count++); +} + /** * Iterates through children that are typically specified as `props.children`. * @@ -237,7 +242,15 @@ function forEachChildren( forEachFunc: () => mixed, forEachContext?: Object, ): void { - mapChildren(children, forEachFunc, forEachContext); + if (children == null) { + return; + } + var traverseContext = { + func: forEachFunc, + context: forEachContext, + count: 0, + }; + traverseAllChildren(children, '', forEachSingleChild, traverseContext); } /** From 4ceb58fb23f32bbf1e3f850a6608c2690688f9f8 Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Tue, 9 May 2017 09:51:06 +0900 Subject: [PATCH 17/21] Remove unnecessary traverseContext --- src/isomorphic/children/ReactChildren.js | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js index 780448d0c3f..eef9988c397 100644 --- a/src/isomorphic/children/ReactChildren.js +++ b/src/isomorphic/children/ReactChildren.js @@ -276,19 +276,7 @@ function countChildren(children: mixed): number { if (children == null) { return 0; } - var traverseContext = { - result: [], - keyPrefix: '', - func: emptyFunction.thatReturns, - context: {}, - count: 0, - }; - return traverseAllChildren( - children, - '', - emptyFunction.thatReturns, - traverseContext, - ); + return traverseAllChildren(children, '', emptyFunction.thatReturnsNull, null); } var ReactChildren = { From 87aefbf30a48994fb6a3b776fe42aa7e1f707c99 Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Tue, 9 May 2017 09:58:32 +0900 Subject: [PATCH 18/21] Record fiber tests --- scripts/fiber/tests-passing.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index 2e36948c29a..06b48abf157 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -41,6 +41,7 @@ scripts/shared/__tests__/evalToString-test.js * should throw when it finds other types src/isomorphic/children/__tests__/ReactChildren-test.js +* should support single child without key * should support identity for simple * should treat single arrayless child as being in array * should treat single child in array as expected From d920c9b79c2789878d1ac4846a0216dfd6993e04 Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Mon, 12 Jun 2017 16:16:52 +0900 Subject: [PATCH 19/21] Rebase #9903 --- src/isomorphic/children/ReactChildren.js | 41 +++++++++++++++++------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js index eef9988c397..dda95776ee8 100644 --- a/src/isomorphic/children/ReactChildren.js +++ b/src/isomorphic/children/ReactChildren.js @@ -13,17 +13,19 @@ 'use strict'; var ReactElement = require('ReactElement'); - var emptyFunction = require('fbjs/lib/emptyFunction'); - -var REACT_ELEMENT_TYPE = require('ReactElementSymbol'); - -var getIteratorFn = require('getIteratorFn'); var invariant = require('fbjs/lib/invariant'); -var KeyEscapeUtils = require('KeyEscapeUtils'); -var warning = require('fbjs/lib/warning'); + +var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; +var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec. +// The Symbol used to tag the ReactElement type. If there is no native Symbol +// nor polyfill, then a plain number is used for performance. +var REACT_ELEMENT_TYPE = + (typeof Symbol === 'function' && Symbol.for && Symbol.for('react.element')) || + 0xeac7; if (__DEV__) { + var warning = require('fbjs/lib/warning'); var {getCurrentStackAddendum} = require('ReactComponentTreeHook'); } @@ -31,10 +33,23 @@ var SEPARATOR = '.'; var SUBSEPARATOR = ':'; /** - * This is inlined from ReactElement since this file is shared between - * isomorphic and renderers. We could extract this to a + * Escape and wrap key so it is safe to use as a reactid * + * @param {string} key to be escaped. + * @return {string} the escaped key. */ +function escape(key: string): string { + var escapeRegex = /[=:]/g; + var escaperLookup = { + '=': '=0', + ':': '=2', + }; + var escapedString = ('' + key).replace(escapeRegex, function(match) { + return escaperLookup[match]; + }); + + return '$' + escapedString; +} var didWarnAboutMaps = false; @@ -46,7 +61,7 @@ function getReactElementKey(element, index) { // that we don't block potential future ES APIs. if (typeof element === 'object' && element !== null && element.key != null) { // Explicit key - return KeyEscapeUtils.escape(element.key); + return escape(element.key); } // Implicit key determined by the index in the set return index.toString(36); @@ -98,8 +113,10 @@ function traverseAllChildren(children, nameSoFar, callback, traverseContext) { ); } } else { - var iteratorFn = getIteratorFn(children); - if (iteratorFn) { + var iteratorFn = + (ITERATOR_SYMBOL && children[ITERATOR_SYMBOL]) || + children[FAUX_ITERATOR_SYMBOL]; + if (typeof iteratorFn === 'function') { if (__DEV__) { // Warn about using Maps as children if (children != null && iteratorFn === children.entries) { From 96b675c6234b939d68124ed90994e68cff1d1403 Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Thu, 15 Jun 2017 13:53:02 +0900 Subject: [PATCH 20/21] Fix flow errors with some $FlowFixMe --- src/isomorphic/children/ReactChildren.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js index dda95776ee8..53252d60681 100644 --- a/src/isomorphic/children/ReactChildren.js +++ b/src/isomorphic/children/ReactChildren.js @@ -67,11 +67,17 @@ function getReactElementKey(element, index) { return index.toString(36); } -function traverseAllChildren(children, nameSoFar, callback, traverseContext) { +function traverseAllChildren( + children: T, + nameSoFar: string, + callback: (context: I, children: T, nameSoFar: string) => void, + traverseContext: I, +) { var type = typeof children; if (type === 'undefined' || type === 'boolean') { // All of the above are perceived as null. + // $FlowFixMe children = null; } @@ -135,9 +141,10 @@ function traverseAllChildren(children, nameSoFar, callback, traverseContext) { var step; var ii = 0; while (iterator && !(step = iterator.next()).done) { - child = step != null && (step.value: ReactElement); + child = step != null ? (step.value: ReactElement) : null; nextName = nextNamePrefix + getReactElementKey(child, ii++); subtreeCount += traverseAllChildren( + // $FlowFixMe child, nextName, callback, @@ -223,7 +230,7 @@ function mapSingleChildIntoContext(bookKeeping, child, childKey) { */ function mapChildren( children: mixed, - func: () => mixed, + func: (child: mixed, count: number) => void, context?: Object, ): ?(mixed[]) { if (children == null) { @@ -256,7 +263,7 @@ function forEachSingleChild(bookKeeping, child, name) { */ function forEachChildren( children: mixed, - forEachFunc: () => mixed, + forEachFunc: (child: mixed, count: number) => void, forEachContext?: Object, ): void { if (children == null) { From 61981da8e40238d821a5b06552519f0e9719dd31 Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Thu, 29 Jun 2017 14:22:42 +0900 Subject: [PATCH 21/21] Fix $FlowFixMe --- src/isomorphic/children/ReactChildren.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js index 53252d60681..5d37ed8d437 100644 --- a/src/isomorphic/children/ReactChildren.js +++ b/src/isomorphic/children/ReactChildren.js @@ -68,16 +68,15 @@ function getReactElementKey(element, index) { } function traverseAllChildren( - children: T, + children: T | null, nameSoFar: string, - callback: (context: I, children: T, nameSoFar: string) => void, + callback: (context: I, children: T | null, nameSoFar: string) => void, traverseContext: I, ) { var type = typeof children; if (type === 'undefined' || type === 'boolean') { // All of the above are perceived as null. - // $FlowFixMe children = null; } @@ -144,7 +143,6 @@ function traverseAllChildren( child = step != null ? (step.value: ReactElement) : null; nextName = nextNamePrefix + getReactElementKey(child, ii++); subtreeCount += traverseAllChildren( - // $FlowFixMe child, nextName, callback,