We ran into a bit of an issue with global variants, and I’m not sure this is something that I have to fix in our code
We have a switch that changes the Mode between light and dark mode (dark is the default, both in code and in plasmic) and if the end-user changes it, it persists to local storage.
This part is working as expected.
This value is provided to the PlasmicRootProvider like this:
Checking with React Developer Tools I found this component and it seems it always gets the proper values.
Despite this, if the user preference is light the components do not respect them after a reload.
(It works as expected when clicking on the toggle switch.)
The issue is with server-side/static pre-rendering of the HTML - it’s always going to be rendering the default variant on the server where it doesn’t know what is the state.
On the client, React simply accepts whatever the server sent as the DOM it needs to hydrate (doesn’t make any changes to the DOM).
One solution is to rerender the correct variant a second time on the client (when it does know the state), via a useEffect(). Note this will result in an initial flash of the wrong theme.
If you’re using getServerSideProps (SSR), you could also find a way to communicate with the server what the stored preference is of the user (e.g. by persisting via cookies), and have the server pre-render the appropriate variant.
I see, we are currently using SSG (getStaticProps), since it is build time, I think the cookie solution won’t work.
(But we might be able to change that, I’ll check.)
Currently, we are using useLocalStorage from usehooks-ts to handle the persistence of the isDarkMode global variable.
(This basically persists the useState variable to localstorage when it changes, it has a default value just like useState has, but it is only used if the user has no value in the local storage for the darkmode) const [isDarkMode] = useLocalStorage('veezla-darkmode', true);
I’m not sure, how does the useEffect would look like?
What should it depend on and what should it do?
Since useLocalStorage is basically a useState it should be enough for the render trigger, am I missing something.