From 9f44251ebf60af8331aaff5ced5629675e04e4bd Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 31 May 2019 14:27:22 +0100 Subject: [PATCH] Remove unnecessary code for host text as we skip it anyway --- src/backend/legacy/getChildren.js | 26 +--- src/backend/legacy/renderer.js | 3 + src/backend/legacy/traverseAllChildrenImpl.js | 146 ------------------ 3 files changed, 5 insertions(+), 170 deletions(-) delete mode 100644 src/backend/legacy/traverseAllChildrenImpl.js diff --git a/src/backend/legacy/getChildren.js b/src/backend/legacy/getChildren.js index 0ce3a39603..0f10b5f282 100644 --- a/src/backend/legacy/getChildren.js +++ b/src/backend/legacy/getChildren.js @@ -1,7 +1,5 @@ // @flow -import traverseAllChildrenImpl from './traverseAllChildrenImpl'; - // TODO (legacy) Respect component filters export default function getChildren(internalInstance: Object): Array { @@ -21,29 +19,9 @@ export default function getChildren(internalInstance: Object): Array { children = [internalInstance._renderedComponent]; } else if (internalInstance._renderedChildren) { children = renderedChildrenToArray(internalInstance._renderedChildren); - } else if ( - internalInstance._currentElement && - internalInstance._currentElement.props - ) { - // This is a native node without rendered children -- meaning the children - // prop is the unfiltered list of children. - // This may include 'null' or even other invalid values, so we need to - // filter it the same way that ReactDOM does. - // Instead of pulling in the whole React library, we just copied over the - // 'traverseAllChildrenImpl' method. - // https://github.com/facebook/react/blob/240b84ed8e1db715d759afaae85033718a0b24e1/src/isomorphic/children/ReactChildren.js#L112-L158 - const unfilteredChildren = internalInstance._currentElement.props.children; - traverseAllChildrenImpl( - unfilteredChildren, - '', // nameSoFar - (_traverseContext, child) => { - const childType = typeof child; - if (childType === 'string' || childType === 'number') { - children.push(child); - } - } - ); } + // Note: we skip the case where children are just strings or numbers + // because the new DevTools skips over host text nodes anyway. const instance = internalInstance._instance; if (instance) { diff --git a/src/backend/legacy/renderer.js b/src/backend/legacy/renderer.js index d8318a9304..1f7edf7d36 100644 --- a/src/backend/legacy/renderer.js +++ b/src/backend/legacy/renderer.js @@ -52,6 +52,9 @@ export function attach( const rootIDs: Set = new Set(); function getID(internalInstance: InternalInstance): number { + if (typeof internalInstance !== 'object') { + throw new Error('Invalid internal instance: ' + internalInstance); + } if (!internalInstanceToIDMap.has(internalInstance)) { const id = getUID(); internalInstanceToIDMap.set(internalInstance, id); diff --git a/src/backend/legacy/traverseAllChildrenImpl.js b/src/backend/legacy/traverseAllChildrenImpl.js deleted file mode 100644 index a7e1cd399c..0000000000 --- a/src/backend/legacy/traverseAllChildrenImpl.js +++ /dev/null @@ -1,146 +0,0 @@ -// @flow - -const SEPARATOR = '.'; -const SUBSEPARATOR = ':'; - -const 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. -const ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; -const REACT_ELEMENT_TYPE = - (typeof Symbol === 'function' && Symbol.for && Symbol.for('react.element')) || - 0xeac7; - -/** - * 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 { - const escapeRegex = /[=:]/g; - const escaperLookup = { - '=': '=0', - ':': '=2', - }; - const escapedString = ('' + key).replace(escapeRegex, function(match) { - return escaperLookup[match]; - }); - - return '$' + escapedString; -} - -/** - * 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 ( - typeof component === 'object' && - component !== null && - component.key != null - ) { - // Explicit key - return escape(component.key); - } - // Implicit key determined by the index in the set - return index.toString(36); -} - -/** - * We do a copied the 'traverseAllChildrenImpl' method from - * `React.Children` so that we don't pull in the whole React library. - * @param {?*} children Children tree container. - * @param {!string} nameSoFar Name of the key path so far. - * @param {!function} callback Callback to invoke with each child found. - * @param {?*} traverseContext Used to pass information throughout the traversal - * process. - * @return {!number} The number of children in this subtree. - */ -export default function traverseAllChildrenImpl( - children: any, - nameSoFar: string, - callback: Function, - traverseContext: any -): number { - const 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; - } - - let child; - let nextName; - let subtreeCount = 0; // Count of children found in the current subtree. - let nextNamePrefix = nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR; - - if (Array.isArray(children)) { - for (let i = 0; i < children.length; i++) { - child = children[i]; - nextName = nextNamePrefix + getComponentKey(child, i); - subtreeCount += traverseAllChildrenImpl( - child, - nextName, - callback, - traverseContext - ); - } - } else { - let iteratorFn = - (ITERATOR_SYMBOL && children[ITERATOR_SYMBOL]) || - children[FAUX_ITERATOR_SYMBOL]; - if (typeof iteratorFn === 'function') { - let iterator = iteratorFn.call(children); - let step; - let ii = 0; - while (!(step = iterator.next()).done) { - child = step.value; - nextName = nextNamePrefix + getComponentKey(child, ii++); - subtreeCount += traverseAllChildrenImpl( - child, - nextName, - callback, - traverseContext - ); - } - } else if (type === 'object') { - let addendum = - ' If you meant to render a collection of children, use an array ' + - 'instead.'; - let childrenString = '' + children; - throw Error( - `The React Devtools cannot render an object as a child. (found: ${ - childrenString === '[object Object]' - ? 'object with keys {' + Object.keys(children).join(', ') + '}' - : childrenString - }). ${addendum}` - ); - } - } - - return subtreeCount; -}