S
SolidJS2mo ago
Eddie

Hydration error when using <Show> in SolidStart

I am new to SolidStart, I see this talked about in several places but I fail to understand how any of the mentioned solutions applies to my case. I am trying to conditionally render something using <Show>:
export function Footer() {
const user = createAsync(() => getUserQuery({}));

return (
<footer>
<Show when={user()}>
<p>
Logged in as: <strong>{user()?.name}</strong>
</p>
</Show>
</footer>
);
}
export function Footer() {
const user = createAsync(() => getUserQuery({}));

return (
<footer>
<Show when={user()}>
<p>
Logged in as: <strong>{user()?.name}</strong>
</p>
</Show>
</footer>
);
}
This results in a hydration error. I am fairly sure that I understand why I'm getting the error, but what pattern should I use to conditionally render an element like this?
5 Replies
peerreynders
peerreynders2mo ago
Try:
export function Footer() {
const user = createAsync(() => getUserQuery({}), { deferStream: true });

return (
<footer>
<Show when={user()}>
{(user) => (
<p>
Logged in as: <strong>{user().name}</strong>
</p>
)}
</Show>
</footer>
);
}
export function Footer() {
const user = createAsync(() => getUserQuery({}), { deferStream: true });

return (
<footer>
<Show when={user()}>
{(user) => (
<p>
Logged in as: <strong>{user().name}</strong>
</p>
)}
</Show>
</footer>
);
}
deferStream
Eddie
EddieOP2mo ago
That does not solve the issue, unfortunately. In my case, the resource user is preloaded on the route that in turn renders this component, so I assume that when the Footer component function runs, it is already a fulfilled promise. - Does this mean that deferStream: true will have no effect here? - Why, if user() is fulfilled when this component mounts, is the when clause in the <Show> not making the content of the <Show> not render on mount (and in turn not cause hydration error because the element is there from the get-go)?
peerreynders
peerreynders2mo ago
Hydration errors only happen after SSR, so the preload doesn't come into play. deferStream: true prevents the page from streaming until the promise accessed by createAsynchas settled, ensuring that the value is available for rendering. The fact that the <Show /> isn't rendering suggests that the promise resolved to a falsy value. One thing you should try is to view to page in incognito as some browser extensions change the DOM which can lead to hydration errors.
Eddie
EddieOP2mo ago
I tried a fresh browser session, it did not help. I have been banging my head against this for some time now and can't figure it out, I ended up doing it this way, which works:
export function Footer() {
const user = createAsync(() => getUserQuery({}), { deferStream: true });

const [hasUser, setHasUser] = createSignal(false);

createEffect(() => {
if (user()) {
setHasUser(true);
}
});

return (
<footer>
<Show when={hasUser()} fallback={<div>User not logged in..</div>}>
{() => {
return <div>Logged in</div>;
}}
</Show>
</footer>
);
}
export function Footer() {
const user = createAsync(() => getUserQuery({}), { deferStream: true });

const [hasUser, setHasUser] = createSignal(false);

createEffect(() => {
if (user()) {
setHasUser(true);
}
});

return (
<footer>
<Show when={hasUser()} fallback={<div>User not logged in..</div>}>
{() => {
return <div>Logged in</div>;
}}
</Show>
</footer>
);
}
If, in the above example, I replace hasUser() with user() in the when clause, I get the hydration error again. I would have preferred to put the user() directly in the when clause, and I am still wondering if I should have been able to.
Madaxen86
Madaxen862mo ago
Can you share the implementation of getUserQuery?

Did you find this page helpful?