Thanks to YCK: Analyze React source code analysis, this article is on the basis of reading his article, his article will be disassembled and processed, add my own understanding and examples, easy to understand. I think yCK’s writing is really good. React version 16.8.6: Yck React source code

React; react; Children react;

In the actual development of React, we rarely use the React.Children API, but we can operate Children and view documents through this API

Let’s take a look at the magic of this API

React.Children.map(this.props.children, c => [[c, c]])
Copy the code

Here’s a look at its actual use in a project:

The console prints the rendered nodes and props as shown below As can be seen from the figure above, thec => [[c, c]]After the transformation, the node becomes:

/ / by c = > [c] [c] transformation after the < div > < p > 1 < / p > < p > 1 < / p > < p > two < / p > < p > two < / p > < / div >Copy the code

The react.children. Map method is actually a mapChildren function. Let’s see how it works inside mapChildren.

function mapChildren(children, func, context) { if (children == null) { return children; } const result = []; mapIntoWithKeyPrefixInternal(children, result, null, func, context); return result; } function mapIntoWithKeyPrefixInternal (children, array, the prefix, func, context) {/ / here is the key, Let escapedPrefix = ''; if (prefix ! = null) { escapedPrefix = escapeUserProvidedKey(prefix) + '/'; } const traverseContext = getPooledTraverseContext( array, escapedPrefix, func, context, ); traverseAllChildren(children, mapSingleChildIntoContext, traverseContext); releaseTraverseContext(traverseContext); }Copy the code

The code in getPooledTraverseContext and releaseTraverseContext introduces the concept of object reuse pools. The purpose of this concept is to maintain a pool of objects of a fixed size, take one object from the pool and assign it, then empty its properties and throw it back into the pool. The purpose of maintaining this pool is to improve performance and avoid frequent creation and destruction of multi-attribute objects.

Although the traverseAllChildren function is called, the traverseAllChildrenImpl method is actually called.

function traverseAllChildrenImpl( children, nameSoFar, callback,traverseContext ) { const type = typeof children; if (type === 'undefined' || type === 'boolean') { children = null; } let invokeCallback = false; if (children === null) { invokeCallback = true; } else { switch (type) { case 'string': case 'number': invokeCallback = true; break; case 'object': switch (children.$$typeof) { case REACT_ELEMENT_TYPE: case REACT_PORTAL_TYPE: invokeCallback = true; } } } if (invokeCallback) { callback( traverseContext, children, nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar, ); return 1; } let child; let nextName; let subtreeCount = 0; const 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 { const iteratorFn = getIteratorFn(children); if (typeof iteratorFn === 'function') { const 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, ); } } } return subtreeCount; }Copy the code

If children is an array, traverseAllChildrenImpl recursively calls the traverseAllChildrenImpl until a single renderable node is processed, and then callback is called. Namely mapSingleChildIntoContext.

Finally let us read mapSingleChildIntoContext function implementation.

function mapSingleChildIntoContext(bookKeeping, child, childKey) { const {result, keyPrefix, func, context} = bookKeeping; let mappedChild = func.call(context, child, bookKeeping.count++); if (Array.isArray(mappedChild)) { mapIntoWithKeyPrefixInternal(mappedChild, result, childKey, c => c); } else if (mappedChild ! = null) { if (isValidElement(mappedChild)) { mappedChild = cloneAndReplaceKey( mappedChild, keyPrefix + (mappedChild.key && (! child || child.key ! == mappedChild.key) ? escapeUserProvidedKey(mappedChild.key) + '/' : '') + childKey, ); } result.push(mappedChild); }}Copy the code

MapSingleChildIntoContext function is called the React. Children. The map (callback in Children, the callback). If after the map or array, then enter mapIntoWithKeyPrefixInternal again, so this time we will once again from the object reuse pool inside to get the context, and the significance of object reuse pool is here, too, if a nested loop is much, You can reduce a lot of object creation and GC waste. If it is not an array, determine whether the value returned is a valid Element. If it is, clone it and replace the key. Finally, put the return value into result, which is the return value of mapChildren.

Here is the order in which the code is called:

MapChildren function | | \ \ | / mapIntoWithKeyPrefixInternal function | / traverseAllChildrenImpl function (renderable cycle into a single node, If not recursive) | | a single node \ | / mapSingleChildIntoContext function (identifying the effective Element to verify through clone and replace the key, and the values into the result, the result is the return value of the map)Copy the code

More:

React. CreateElement (1)

Reference:

React source code

Jokcy react.jokcy. Me /

See more blog posts:

Personal gold digging more articles link jump;

GitHub blog project links to more articles jump;