As the title states, using React.cloneElement
inside React.Children.map
is causing element keys to change.
Here is a sandbox demonstrating this.
React.Children.map(children, (child) => {
let clonedEl = React.cloneElement( child );
console.log(clonedEl);
return clonedEl;
});
The result of that block of code has elements with .$
added to the front of every key. This is really confusing for two reasons.
1: The documentation says that cloneElement will preserve keys and refs.
Clone and return a new React element using element as the starting point. The resulting element will have the original element’s props with the new props merged in shallowly. New children will replace existing children. key and ref from the original element will be preserved.
2: The results of the console.log
is an element with preserved keys and ref...
This would lead me to believe that the addition is happening somewhere in the React.Children.map code.
UPDATE: After looking at the code for React.Children.map...
I figured out it is getting added by the following function chain: mapChilren -> mapIntoWithKeyPrefixInternal -> traverseAllChildren -> traverseAllChildrenImpl -> mapSingleChildIntoContext.
mapSingleChildIntoContext
's third argument is childKey. It is called with nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar
as it's third argument inside traverseAllChildrenImpl
.
SEPARATOR = "."
and getComponentKey
returns the key with a $ prefixed to it within the escape function.
UPDATED PROBLEM:
Now I'm looking for a way around this... I'm not sure if there is one considering traverseAllChildrenImpl is called with an empty string as the nameSoFar
within traverseAllChildren.
I think this may be intended the intended behavior of React.Children.map
to build new DOM. This is causing a for me when trying to update the props on dynamic children.
SOLUTION: Don't use things how they're not intended to be used.
I was building a grouping of form controls that are really easy for the developer. The state tree is dynamically built by mapping the children and using . delineated string names from elements with names to create keys and values on the top level component.
The top level form component has onChange handlers for different types of controls and they are applied to the onChange properties of elements as needed. This mapping was done in the componentWillMount method and is what was causing me problems.
Moving the mapping to the render method allowed me to not have to update the children in the handles. Updating in the handles was causing elements to lose focus. All is good now!
React.Children.forEach
as an alternative. – Prakash Sharma