S
SolidJS14mo ago
Mathieu

How to get the first child out of `props.children`?

I think in React it is done like so: React.Children.toArray(props.children)[0] What would be the equivalent in SolidJS?
32 Replies
Alex Lohr
Alex Lohr14mo ago
children(() => Array.isArray(props.children) ? props.children[0] : props.children)
Mathieu
Mathieu14mo ago
TY!
Otonashi
Otonashi14mo ago
that would access props.children twice and not really work if props.children is an accessor, imo you should use
const resolved = children(() => props.children);
const firstChild = resolved.toArray()[0];
const resolved = children(() => props.children);
const firstChild = resolved.toArray()[0];
Mathieu
Mathieu14mo ago
Thank you! I can't use resolved in the jsx though (Type 'ChildrenReturn' is not assignable to type 'Element'). I have to use props.children and firstChild. That's okay? I'm asking because I don't see why you assigned to an intermediary variable resolved. except to make the steps more clear maybe.
Otonashi
Otonashi14mo ago
i mean you want to get the first child right? that's what firstChild is or well okay i guess i should write const firstChild = () => resolved.toArray()[0] then invoke it in the jsx resolved should also be used as resolved() fyi, if you were confused about that
Mathieu
Mathieu14mo ago
@otonashi9 I want both the first child and the children separately. But now you changed firstChild from a jsx element to a function?
Otonashi
Otonashi14mo ago
execute it in the jsx otherwise it won't be reactive or in an effect, etc
Mathieu
Mathieu14mo ago
thank you, so I have
const firstChild = () => children(() => props.children).toArray()[0];
const firstChild = () => children(() => props.children).toArray()[0];
and in the jsx:
<div>
{firstChild()}
</div>
<div>
{props.children}
</div>
<div>
{firstChild()}
</div>
<div>
{props.children}
</div>
does that look good @otonashi9 ?
Otonashi
Otonashi14mo ago
use resolved() instead of props.children
Mathieu
Mathieu14mo ago
ahhhh
Otonashi
Otonashi14mo ago
otherwise you'll be accessing props.children twice and you don't want to do that because you'll end up creating it twice
Mathieu
Mathieu14mo ago
If I understand correctly, accessing props.children creates the jsx elements, and I was accessing it twice (once to access first child through children() helper, and once calling props.children in the jsx). Secondly, you mentioned I need to wrap the first child in a function, to make it reactive. So that means that JSX elements follow the same rules as signals. It's all a bit abstract for me, you seem really deep into it.
Otonashi
Otonashi14mo ago
you can treat all props as signals where the access is in the getter like it's all signals, rather than jsx elements following a rule
Mathieu
Mathieu14mo ago
@otonashi9 I just noticed that my UI broke:
const resolvedChildren = children(() => props.children);

const firstChild1 = () => resolvedChildren.toArray()[0];

const firstChild2 = () => children(() => props.children).toArray()[0];
const resolvedChildren = children(() => props.children);

const firstChild1 = () => resolvedChildren.toArray()[0];

const firstChild2 = () => children(() => props.children).toArray()[0];
<div>{firstChild1()}</div>
<div>{firstChild2()}</div>
<div>{firstChild1()}</div>
<div>{firstChild2()}</div>
The call to firstChild1 doesn't work (nothing on the screen, but when calling console log before returning the jsx I see the element though) but firstChild2 works. The problem is I create two times the children with firstChild2 call.
Otonashi
Otonashi14mo ago
can you reproduce it?
Otonashi
Otonashi14mo ago
🤔
Mathieu
Mathieu14mo ago
I didn't expect that from you. Now I'm worried 😂
Otonashi
Otonashi14mo ago
oh i see it's because you're using resolvedChildren as well so you're trying to mount the first child in two places
Mathieu
Mathieu14mo ago
yes
Otonashi
Otonashi14mo ago
which doesn't work, it can only be in one place at once
Mathieu
Mathieu14mo ago
I need that
Otonashi
Otonashi14mo ago
hmm then you have to create the children twice i guess if you need two copies of the same div
Mathieu
Mathieu14mo ago
I have to think for 2 mins I can't just re-create only the first child from resolvedChildren? If I recall correectly, SolidJS doesn't have the cloning like React, so my guess is no.
Otonashi
Otonashi14mo ago
you can't, since props.children will create all the children you can use cloneNode maybe, but then it won't update when the other one does and it doesn't seem very compatible with ssr either is there any reason why you have to use the first child instead of a separate prop?
Mathieu
Mathieu14mo ago
Just briefly explain to you, I have toggle buttons like so:
Button A | Button B | Button C
I make this components mobile responsive, it can transform into a dropdown, like so:
Button A ↓ Button A Button B Button C
You can see above, in dropdown mode (for mobiles), Button A is repeated twice. It's also obviously because I use children like so:
<ToggleButton.Group
isDropdown={viewport.width === Viewport.SmallWidth}
onChange={handleChange}
selectedValue={value()}
>
<ToggleButton value="revenues">{translate('revenues')}</ToggleButton>
<ToggleButton value="expenses">{translate('expenses')}</ToggleButton>
<ToggleButton value="internal_transfers">{translate('internal_transfers')}</ToggleButton>
</ToggleButton.Group>
<ToggleButton.Group
isDropdown={viewport.width === Viewport.SmallWidth}
onChange={handleChange}
selectedValue={value()}
>
<ToggleButton value="revenues">{translate('revenues')}</ToggleButton>
<ToggleButton value="expenses">{translate('expenses')}</ToggleButton>
<ToggleButton value="internal_transfers">{translate('internal_transfers')}</ToggleButton>
</ToggleButton.Group>
Anyway I will just re-create the children because they are not expensive at all... But I wanted to share you my use case @otonashi9 do you have any further critic?
Otonashi
Otonashi14mo ago
it's fine, the concern with creating the children more than once is if there are any side effects those will also run more than once which may be undesirable
Mathieu
Mathieu14mo ago
thing is, I want to keep this API/DX. Of course if I change the API to make it work more smoothly it's easier.
Otonashi
Otonashi14mo ago
like there are ways to implement it to avoid the problem e.g. you don't pass ToggleButtons at all but just a list of strings, but if this works for you then it works
Mathieu
Mathieu14mo ago
btw you don't use twitter, I cannot follow you anywhere?
Otonashi
Otonashi14mo ago
nope
Mathieu
Mathieu14mo ago
you seem to be very private guy hehe ok thank you so muuuch for the help, as usual 🤍