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 Lohr2y ago
children(() => Array.isArray(props.children) ? props.children[0] : props.children)
Mathieu
MathieuOP2y ago
TY!
Otonashi
Otonashi2y 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
MathieuOP2y 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
Otonashi2y 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
MathieuOP2y 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
Otonashi2y ago
execute it in the jsx otherwise it won't be reactive or in an effect, etc
Mathieu
MathieuOP2y 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
Otonashi2y ago
use resolved() instead of props.children
Mathieu
MathieuOP2y ago
ahhhh
Otonashi
Otonashi2y 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
MathieuOP2y 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
Otonashi2y 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
MathieuOP2y 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
Otonashi2y ago
can you reproduce it?
Otonashi
Otonashi2y ago
🤔
Mathieu
MathieuOP2y ago
I didn't expect that from you. Now I'm worried 😂
Otonashi
Otonashi2y 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
MathieuOP2y ago
yes
Otonashi
Otonashi2y ago
which doesn't work, it can only be in one place at once
Mathieu
MathieuOP2y ago
I need that
Otonashi
Otonashi2y ago
hmm then you have to create the children twice i guess if you need two copies of the same div
Mathieu
MathieuOP2y 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
Otonashi2y 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
MathieuOP2y 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
Otonashi2y 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
MathieuOP2y 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
Otonashi2y 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
MathieuOP2y ago
btw you don't use twitter, I cannot follow you anywhere?
Otonashi
Otonashi2y ago
nope
Mathieu
MathieuOP2y ago
you seem to be very private guy hehe ok thank you so muuuch for the help, as usual 🤍
Want results from more Discord servers?
Add your server