Solidstart Hydration error when using show and jsx element

I am moving my project to solidstart and i having an error with this component
interface ArrowButtonProps extends AnchorProps {
prefixIcon?: JSX.Element;
variant?: "primary" | "default";
}

export const ArrowButton: ParentComponent<ArrowButtonProps> = (
initialProps
) => {
const allProps = mergeProps(
{
variant: "default",
} satisfies Partial<ArrowButtonProps>,
initialProps
);
const [props, anchorProps] = splitProps(allProps, [
"prefixIcon",
"variant",
"children",
]);

return (
<A
{...anchorProps}
class={clsx(
"flex items-center sm:gap-5 gap-2 bg-background-60 rounded-2xl p-3 sm:pl-5 sm:pr-10 px-5 hover:cursor-pointer group hover:bg-background-50 opacity-95 transition-colors border",
props.variant === "primary"
? "border-status-success"
: "border-background-30"
)}
>
<Show when={props.prefixIcon}>
<div
class={clsx(
"w-12 justify-center group-hover:fill-status-success fill-white hidden sm:flex"
)}
>
{props.prefixIcon}
</div>
</Show>
<div class="flex flex-col flex-grow">{props.children}</div>
<div class="flex w-9 group-hover:translate-x-5 transition-transform duration-200">
<ArrowIcon
class="fill-background-10"
size={30}
direction="right"
></ArrowIcon>
</div>
</A>
);
};
interface ArrowButtonProps extends AnchorProps {
prefixIcon?: JSX.Element;
variant?: "primary" | "default";
}

export const ArrowButton: ParentComponent<ArrowButtonProps> = (
initialProps
) => {
const allProps = mergeProps(
{
variant: "default",
} satisfies Partial<ArrowButtonProps>,
initialProps
);
const [props, anchorProps] = splitProps(allProps, [
"prefixIcon",
"variant",
"children",
]);

return (
<A
{...anchorProps}
class={clsx(
"flex items-center sm:gap-5 gap-2 bg-background-60 rounded-2xl p-3 sm:pl-5 sm:pr-10 px-5 hover:cursor-pointer group hover:bg-background-50 opacity-95 transition-colors border",
props.variant === "primary"
? "border-status-success"
: "border-background-30"
)}
>
<Show when={props.prefixIcon}>
<div
class={clsx(
"w-12 justify-center group-hover:fill-status-success fill-white hidden sm:flex"
)}
>
{props.prefixIcon}
</div>
</Show>
<div class="flex flex-col flex-grow">{props.children}</div>
<div class="flex w-9 group-hover:translate-x-5 transition-transform duration-200">
<ArrowIcon
class="fill-background-10"
size={30}
direction="right"
></ArrowIcon>
</div>
</A>
);
};
Error
Error: Hydration Mismatch. Unable to find DOM nodes for hydration key: 0000000000100000000000840100
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M0 24C0 10.7 10.7 0 24 0L69.5 0c22 0 41.5 12.8 50.6 32l411 0c26.3 0 45.5 25 38.6 50.4l-41 152.3c-8.5 31.4-37 53.3-69.5 53.3l-288.5 0 5.4 28.5c2.2 11.3 12.1 19.5 23.6 19.5L488 336c13.3 0 24 10.7 24 24s-10.7 24-24 24l-288.3 0c-34.6 0-64.3-24.6-70.7-58.5L77.4 54.5c-.7-3.8-4-6.5-7.9-6.5L24 48C10.7 48 0 37.3 0 24zM128 464a48 48 0 1 1 96 0 48 48 0 1 1 -96 0zm336-48a48 48 0 1 1 0 96 48 48 0 1 1 0-96z"></path></svg>
at getNextElement (chunk-JUDL6WSM.js?v=09a49709:287:13)
at CartIcon.tsx:4:3
at _$$component.location (CartIcon.tsx:9:25)
at @solid-refresh:25:42
at untrack (chunk-47UY6I3P.js?v=09a49709:456:12)
at HMRComp.createMemo.name [as fn] (@solid-refresh:25:28)
at runComputation (chunk-47UY6I3P.js?v=09a49709:721:22)
at updateComputation (chunk-47UY6I3P.js?v=09a49709:703:3)
at createMemo (chunk-47UY6I3P.js?v=09a49709:265:10)
at [solid-refresh]CartIcon (@solid-refresh:22:20)
Error: Hydration Mismatch. Unable to find DOM nodes for hydration key: 0000000000100000000000840100
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M0 24C0 10.7 10.7 0 24 0L69.5 0c22 0 41.5 12.8 50.6 32l411 0c26.3 0 45.5 25 38.6 50.4l-41 152.3c-8.5 31.4-37 53.3-69.5 53.3l-288.5 0 5.4 28.5c2.2 11.3 12.1 19.5 23.6 19.5L488 336c13.3 0 24 10.7 24 24s-10.7 24-24 24l-288.3 0c-34.6 0-64.3-24.6-70.7-58.5L77.4 54.5c-.7-3.8-4-6.5-7.9-6.5L24 48C10.7 48 0 37.3 0 24zM128 464a48 48 0 1 1 96 0 48 48 0 1 1 -96 0zm336-48a48 48 0 1 1 0 96 48 48 0 1 1 0-96z"></path></svg>
at getNextElement (chunk-JUDL6WSM.js?v=09a49709:287:13)
at CartIcon.tsx:4:3
at _$$component.location (CartIcon.tsx:9:25)
at @solid-refresh:25:42
at untrack (chunk-47UY6I3P.js?v=09a49709:456:12)
at HMRComp.createMemo.name [as fn] (@solid-refresh:25:28)
at runComputation (chunk-47UY6I3P.js?v=09a49709:721:22)
at updateComputation (chunk-47UY6I3P.js?v=09a49709:703:3)
at createMemo (chunk-47UY6I3P.js?v=09a49709:265:10)
at [solid-refresh]CartIcon (@solid-refresh:22:20)
After trial and error i have pinpointed the error to this section
<Show when={props.prefixIcon}>
<div
class={clsx(
"w-12 justify-center group-hover:fill-status-success fill-white hidden sm:flex"
)}
>
{props.prefixIcon}
</div>
</Show>
<Show when={props.prefixIcon}>
<div
class={clsx(
"w-12 justify-center group-hover:fill-status-success fill-white hidden sm:flex"
)}
>
{props.prefixIcon}
</div>
</Show>
When using Show for the prefixIcon i get the current error but if i remove the Show tag (put still use prefix icon) the error is completely gone. Can someone tell me what am i missing?
10 Replies
Jasmin
Jasmin2w ago
where do you set prefixIcon? Looks like it's different on the server vs. the client
loucass003
loucass003OP2w ago
<ArrowButton
variant="primary"
prefixIcon={<CartIcon size={60}></CartIcon>}
href="/"
>
<div class="flex flex-col flex-wrap relative justify-center pb-2">
<div
class="absolute -top-12 sm:-top-14 -left-6 sm:-left-[6.8rem] w-fit rotate-[-10deg] text-2xl sm:text-4xl p-1 rounded-md shadow-lg shadow-accent-background-40 font-bold bg-accent-background-20"
style={{
"box-shadow":
"#4e0097 0.5rem 0.5rem, rgb(241 241 241) -0.5rem -0.5rem",
}}
>
{/* <Localized id="hero_price" /> */}
</div>
<Typography
variant="main-title"
tag="h3"
whitespace="whitespace-nowrap"
key="hero_order-btn"
/>
<CrowdSupplyIcon size={256}></CrowdSupplyIcon>
</div>
</ArrowButton>
<ArrowButton
variant="primary"
prefixIcon={<CartIcon size={60}></CartIcon>}
href="/"
>
<div class="flex flex-col flex-wrap relative justify-center pb-2">
<div
class="absolute -top-12 sm:-top-14 -left-6 sm:-left-[6.8rem] w-fit rotate-[-10deg] text-2xl sm:text-4xl p-1 rounded-md shadow-lg shadow-accent-background-40 font-bold bg-accent-background-20"
style={{
"box-shadow":
"#4e0097 0.5rem 0.5rem, rgb(241 241 241) -0.5rem -0.5rem",
}}
>
{/* <Localized id="hero_price" /> */}
</div>
<Typography
variant="main-title"
tag="h3"
whitespace="whitespace-nowrap"
key="hero_order-btn"
/>
<CrowdSupplyIcon size={256}></CrowdSupplyIcon>
</div>
</ArrowButton>
this is how i use the component
Jasmin
Jasmin2w ago
I think prefixIcon should be a component (function) or it'll generate twice with different hydration ids
prefixIcon={() => <CartIcon size={60}></CartIcon>}
prefixIcon={() => <CartIcon size={60}></CartIcon>}
try this
loucass003
loucass003OP2w ago
but that means my type cannot be a JSX element anymore but a component right?
Jasmin
Jasmin2w ago
yeah it'll be a component () => JSX.Element and you have to call it in the jsx
loucass003
loucass003OP2w ago
yeah like this
<Show when={props.prefixIcon}>
<div
class={clsx(
"w-12 justify-center group-hover:fill-status-success fill-white hidden sm:flex"
)}
>
{props.prefixIcon()}
</div>
</Show>
<Show when={props.prefixIcon}>
<div
class={clsx(
"w-12 justify-center group-hover:fill-status-success fill-white hidden sm:flex"
)}
>
{props.prefixIcon()}
</div>
</Show>
that does fix the issue indeed
Jasmin
Jasmin2w ago
nice
loucass003
loucass003OP2w ago
this changes the syntax used for a lot of things then. I am surprised solidstart require changes this big in the writing of component. espectially when all the solidjs example tells you tu use JSX.Element almost all the time for that specific case
Brendonovich
Brendonovich2w ago
Note that it's not really a problem with Start, it's just a general SSR thing. Without providing a function, each time props.prefixIcon is ran its JSX is re-evaluated, so in your case it was running twice, and hydration was expecting two icons to be present in the HTML. You can avoid this by using a function instead as you've seen, or by ensuring props.prefixIcon doesn't get evaluated twice. You'll want to use the children helper for this, as it will memoise the component.
import { children } from "solid-js";

export const ArrowButton: ParentComponent<ArrowButtonProps> = (
initialProps
) => {
const allProps = mergeProps(
{
variant: "default",
} satisfies Partial<ArrowButtonProps>,
initialProps
);
const [props, anchorProps] = splitProps(allProps, [
"prefixIcon",
"variant",
"children",
]);

const prefixIcon = children(() => props.prefixIcon)

return (
<A
{...anchorProps}
class={clsx(
"flex items-center sm:gap-5 gap-2 bg-background-60 rounded-2xl p-3 sm:pl-5 sm:pr-10 px-5 hover:cursor-pointer group hover:bg-background-50 opacity-95 transition-colors border",
props.variant === "primary"
? "border-status-success"
: "border-background-30"
)}
>
<Show when={prefixIcon()}>
<div
class={clsx(
"w-12 justify-center group-hover:fill-status-success fill-white hidden sm:flex"
)}
>
{prefixIcon()}
</div>
</Show>
<div class="flex flex-col flex-grow">{props.children}</div>
<div class="flex w-9 group-hover:translate-x-5 transition-transform duration-200">
<ArrowIcon
class="fill-background-10"
size={30}
direction="right"
></ArrowIcon>
</div>
</A>
);
};
import { children } from "solid-js";

export const ArrowButton: ParentComponent<ArrowButtonProps> = (
initialProps
) => {
const allProps = mergeProps(
{
variant: "default",
} satisfies Partial<ArrowButtonProps>,
initialProps
);
const [props, anchorProps] = splitProps(allProps, [
"prefixIcon",
"variant",
"children",
]);

const prefixIcon = children(() => props.prefixIcon)

return (
<A
{...anchorProps}
class={clsx(
"flex items-center sm:gap-5 gap-2 bg-background-60 rounded-2xl p-3 sm:pl-5 sm:pr-10 px-5 hover:cursor-pointer group hover:bg-background-50 opacity-95 transition-colors border",
props.variant === "primary"
? "border-status-success"
: "border-background-30"
)}
>
<Show when={prefixIcon()}>
<div
class={clsx(
"w-12 justify-center group-hover:fill-status-success fill-white hidden sm:flex"
)}
>
{prefixIcon()}
</div>
</Show>
<div class="flex flex-col flex-grow">{props.children}</div>
<div class="flex w-9 group-hover:translate-x-5 transition-transform duration-200">
<ArrowIcon
class="fill-background-10"
size={30}
direction="right"
></ArrowIcon>
</div>
</A>
);
};
loucass003
loucass003OP2w ago
thank you for this explaination. I do find your solution nicer to use! thanks ❤️
Want results from more Discord servers?
Add your server