Closed NexRX closed 1 month ago
Hi all, this has been sitting here for a bit now. Anything I can do to contribute to fixing this? :)
Well trying to decide what to do here. Solid is acting exactly how I'd expect it to. But I can see why the situation is awkward. Server renders dark, it hydrates thinking light, it assumes it matches which it doesn't and we don't do corrections. Then when you toggle it to light.. the client already thinks it is light so it doesn't propagate any change.. You have to change it to dark to change it to light again.
Your best bet is to have the server and client always match on initial render and then have the localStorage kick in. Which means it needs to hydrate dark. Which means nano-stores persistent atom isn't helping you here.
Changing your component to this works:
const nanoTheme = useStore($theme);
const [theme, setTheme] = createSignal("dark")
createEffect(() => {
setTheme(nanoTheme())
})
return (<li class="link-card">
<h2>
Active Theme
</h2>
<p>
{theme()} <br />
Dark?:
<input type="checkbox" checked={theme() === "dark"} onChange={(e) => {
$theme.set(e.target.checked ? "dark" : "light")
}} />
<br />
<button onClick={() => console.log(`Atom value = '${$theme.get()}' | Store value = '${theme()}'`)}>Log Theme State</button>
</p>
</li>
But it does feel a bit like it isn't leveraging the the niceness of what nanostores is trying to offer. That being said persistent store as a source of truth with hydration seems like it isn't a good pattern in general.
Yeah the more I look at this the more I can't say this is a bug. Persistent storage is always going to cause rendering to not match unless you apply it after mount/hydration.
Ah okay, thanks for the insight at least. What would be your goto for applying after mount? I tried using createEffect/onMount but had no luck. I assume you mean post the point of a onMount triggering and running?
No I meant onMount
or createEffect
. I edited the example and it seemed to switch fine. The problem is that the persistent nanostores start in the "correct" state which is wrong for hydration. So the server rendering and the client have to start at the fixed value and then apply the localStorage after. Typically in Solid I'd just be doing this by directly grabbing from localStorage in a onMount
but given that the desire in your example was for nanostores to stay in sync I did that sort of createEffect
syncing thing. Since I can't imagine this toggle is a hyper performance area the fact it writes in an effect should be fine.
Describe the bug
When SSRing with state and that state is updated on the client immediately/onMount, the new value is not reflected in the DOM.
Your Example Website or App
https://stackblitz.com/~/github.com/NexRX/astro-solid-nanostore
Steps to Reproduce the Bug or Issue
Using my example which demos a simple theme toggle defaulting to 'dark' mode...
Expected behavior
When the client takes over after SSR the DOM reflect the updated state from onMount
Screenshots or Videos
Platform
Additional context
client:only
the problem goes away (but not ideal)