I was trying to modify and clone child elements of a component I am creating and recently noticed that the type of children
I was getting changed depending on how I pass the children
.
For example if I pass JSX as a children:
<MyComponent>
<div>Hello</div>
</MyComponent>
When I check for the children
structure within MyComponent
I can see that the object is as follow:
{
'$$typeof': Symbol(react.element),
type: 'div',
key: null,
ref: null,
props: { children: 'hello' },
_owner: null,
_store: {}
}
This can be directly used by React.cloneElement
since props.children
is present.
If instead I create a functional component like this:
const Hello: React.FC = () => <div>hello</div>;
And try to use it like this:
<MyComponent>
<Hello/>
</MyComponent>
Then the structure of the children
object becomes this:
{
'$$typeof': Symbol(react.element),
type: [Function: Hello],
key: null,
ref: null,
props: {},
_owner: null,
_store: {}
}
I can no longer use React.cloneElement
unless I call children.type()
which I could not find much documentation on.
Why is this happening and is this expected? And is calling children.type()
the only way to clone the entire tree of child elements?
2
Answers
I just found my own answer after poking around... apprently the more standard way is to use
React.Children.map
. Based on my original example:If I call this from
<MyComponent>
:Then I have the same object, without calling
.type()
:<div>Hello</div>
is a div,<Hello/>
is a function that returns a div so obviously they are not the same thing.<Hello/>
has an empty object asprops
because it has no children and we didn’t pass it an attribute with a value soprops
is{}
.what you want really access and clone, is the children of the parent JSX element returned by
<Hello/>
this has nothing to do with its props.the parent JSX element returned is in fact
children.type()
(what the function returns) this element has childrens wrapped within it (Hello) sochildren.type().props.children
is also present there,so you can clone it.