S
SolidJS2mo ago
RATIU5

Solid.js does not render children in a `<For>` loop correctly

Take a look at my component code:
type CartProps = {
cartIcon: JSX.Element;
trashIcon: JSX.Element;
};

const Cart: Component<CartProps> = (props) => {
const cartItems = useStore(cartItemsStore);

return (
<Sheet>
<SheetTrigger class="relative">
{props.cartIcon}
{cartItems().length > 0 && (
<div class="absolute top-1 right-1 -mt-2 -mr-2 bg-red-500 text-white text-xs rounded-full w-4 h-4 flex items-center justify-center">
{cartItems().reduce((acc, item) => acc + item.quantity, 0)}
</div>
)}
</SheetTrigger>
<SheetContent>
<For each={cartItems()}>
{(item) => (
<div class="w-full p-2 flex justify-between">
<div class="grid grid-flow-col gap-4">
<p class="grid-cols-1">{item.title}</p>
<p class="grid-cols-1 text-neutral-600">x{item.quantity}</p>
</div>
<div>
{/* problem is happening here */}
<button class="text-neutral-500">{props.trashIcon}</button>
</div>
</div>
)}
</For>
</SheetContent>
</Sheet>
);
};
type CartProps = {
cartIcon: JSX.Element;
trashIcon: JSX.Element;
};

const Cart: Component<CartProps> = (props) => {
const cartItems = useStore(cartItemsStore);

return (
<Sheet>
<SheetTrigger class="relative">
{props.cartIcon}
{cartItems().length > 0 && (
<div class="absolute top-1 right-1 -mt-2 -mr-2 bg-red-500 text-white text-xs rounded-full w-4 h-4 flex items-center justify-center">
{cartItems().reduce((acc, item) => acc + item.quantity, 0)}
</div>
)}
</SheetTrigger>
<SheetContent>
<For each={cartItems()}>
{(item) => (
<div class="w-full p-2 flex justify-between">
<div class="grid grid-flow-col gap-4">
<p class="grid-cols-1">{item.title}</p>
<p class="grid-cols-1 text-neutral-600">x{item.quantity}</p>
</div>
<div>
{/* problem is happening here */}
<button class="text-neutral-500">{props.trashIcon}</button>
</div>
</div>
)}
</For>
</SheetContent>
</Sheet>
);
};
The props.trashIcon is only rendering once in this loop for the last item only. How can I get it to render for every element? I've tried everything I could think of like making it a safe child and wrapping it in functions and nothing has worked. Is this possible or a bug?
20 Replies
RATIU5
RATIU5OP2mo ago
For extra information, I am using this as a framework component from within Astro, and trashIcon is coming as a named slot from Astro. I don't think this has anything to do with this problem, but it could.
REEEEE
REEEEE2mo ago
Try making props.trashIcon a function
RATIU5
RATIU5OP2mo ago
Tried this: const renderTrashIcon = () => props.trashIcon;, still results in one (the last) icon being rendered in the list.
REEEEE
REEEEE2mo ago
Is it possible to update the original props.trashIcon to be a function instead?
RATIU5
RATIU5OP2mo ago
Are you saying to make the prop passed into this component a function? So the new props type would look like this?
type CartProps = {
cartIcon: JSX.Element;
trashIcon: () => JSX.Element;
};
type CartProps = {
cartIcon: JSX.Element;
trashIcon: () => JSX.Element;
};
I haven't found a successful way to do that, as Astro is handling the prop injection. I just get a JSX-like element from the props object.
REEEEE
REEEEE2mo ago
Hm okay I see, the reason I was suggesting it and what is most likely the origin of the problem is that you can't render the same html node in multiple spots. If you don't mind a slightly messy possible solution, make a function that reads in the trash icon and manually calls cloneNode on it and then using that returned value in the jsx. I've never done this before but it might work for this case and should be fine since it's just an icon
RATIU5
RATIU5OP2mo ago
Oh really? Hmm. May have to see if this might be a bug in the Astro community. Or if there is a certain way to accomplish this in Solid that's more "standard" when dealing with this problem. Thanks for the suggestion. I'll give that a try now. Darn, I get TypeError: props.trashIcon.cloneNode is not a function. I feel like this is a common problem. Maybe not. I'm still digging through docs to see if there is anything said about this.
REEEEE
REEEEE2mo ago
what does logging props.trashIcon give you?
RATIU5
RATIU5OP2mo ago
It gives me a DOM element/node that looks like this:
<astro-slot name="trashIcon">
<svg
width="20"
height="20"
viewBox="0 0 24 24"
slot="trashIcon"
data-icon="trash"
data-astro-source-file="/path/to/project/node_modules/.pnpm/[email protected]/node_modules/astro-icon/components/Icon.astro"
data-astro-source-loc="117:44"
>
<symbol
id="ai:local:trash"
data-astro-source-file="/path/to/project/node_modules/.pnpm/[email protected]/node_modules/astro-icon/components/Icon.astro"
data-astro-source-loc="124:28"
><g
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
><path stroke="none" d="M0 0h24v24H0z"></path><path
d="M4 7h16m-10 4v6m4-6v6M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2l1-12M9 7V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3"
></path></g
></symbol
><use
xlink:href="#ai:local:trash"
data-astro-source-file="/path/to/project/node_modules/.pnpm/[email protected]/node_modules/astro-icon/components/Icon.astro"
data-astro-source-loc="125:10"></use>
</svg>
</astro-slot>
<astro-slot name="trashIcon">
<svg
width="20"
height="20"
viewBox="0 0 24 24"
slot="trashIcon"
data-icon="trash"
data-astro-source-file="/path/to/project/node_modules/.pnpm/[email protected]/node_modules/astro-icon/components/Icon.astro"
data-astro-source-loc="117:44"
>
<symbol
id="ai:local:trash"
data-astro-source-file="/path/to/project/node_modules/.pnpm/[email protected]/node_modules/astro-icon/components/Icon.astro"
data-astro-source-loc="124:28"
><g
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
><path stroke="none" d="M0 0h24v24H0z"></path><path
d="M4 7h16m-10 4v6m4-6v6M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2l1-12M9 7V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3"
></path></g
></symbol
><use
xlink:href="#ai:local:trash"
data-astro-source-file="/path/to/project/node_modules/.pnpm/[email protected]/node_modules/astro-icon/components/Icon.astro"
data-astro-source-loc="125:10"></use>
</svg>
</astro-slot>
REEEEE
REEEEE2mo ago
maybe it's because of the astro slot, weird
RATIU5
RATIU5OP2mo ago
I'll file a bug report on the Astro side. See if this is a probem with the rendering/transformation of Astro components to Solid.js components.
RATIU5
RATIU5OP2mo ago
For posterity looking more into this problem, more info will be tracked here: https://github.com/withastro/astro/issues/12212
GitHub
[@astrojs/solid-js] Passing in children (or named slots) won't be r...
Astro Info Astro v4.15.11 Node v22.9.0 System macOS (arm64) Package Manager pnpm Output hybrid Adapter none Integrations @astrojs/solid-js @astrojs/tailwind astro-icon If this issue only occurs in ...
mdynnl
mdynnl2mo ago
I think they stated this is not supported https://docs.astro.build/en/basics/astro-components/#named-slots without actually seeing your code, you probably are using this component directly in astro, right? using astro's named slots
RATIU5
RATIU5OP2mo ago
mdynnl
mdynnl2mo ago
yes, exactly
RATIU5
RATIU5OP2mo ago
If I am understanding you, I think so
mdynnl
mdynnl2mo ago
instead of doing that, you could just render the icon using solid instead of astro's named slots though I'm not sure if that's even supported
RATIU5
RATIU5OP2mo ago
That's true. It also happens with children as well. If this can't be fixed, I guess I can just render them with Solid instead.
mdynnl
mdynnl2mo ago
not implying that this can't be fixed
RATIU5
RATIU5OP2mo ago
Well thanks for both of your assistance!
Want results from more Discord servers?
Add your server