3

I created a <ThemeProvider/> using useContext with React. Everything works fine in development environment. I'm able to pass colors down to components, and store the selected color theme in localStorage using the useEffect hook (theme color can be selected by clicking on a button). Then the selected theme color can be retrieved from localStorage after refresh.

I managed to deploy the website on Netlify, and what I've written in dev environment for local storage now doesn't behave the same way. I'm now unable to retrieve selected theme color from local storage.

Here is the a code snippet:

const [state, setState] = useState({
       count: 0,
       mainColor: themesArray[getTheme()].mainColor,
       secondColor: themesArray[getTheme()].secondColor,
       thirdColor: themesArray[getTheme()].thirdColor,
       mainFilter: themesArray[getTheme()].mainFilter,
       secondFilter: themesArray[getTheme()].secondFilter,
       boxShadowRGB1: themesArray[getTheme()].boxShadowRGB1,
       boxShadowRGB2: themesArray[getTheme()].boxShadowRGB2,
       boxShadowRGB3: themesArray[getTheme()].boxShadowRGB3
   });

useEffect(() => {
   localStorage.setItem('theme', JSON.stringify(state.count));
}, [state.count]);

function getTheme() {
   if (typeof window === 'object' || typeof window !== 'undefined') {
       const savedTheme = JSON.parse(localStorage.getItem('theme'));
       return savedTheme || 0;
   } else return 0;
}

In getTheme() method, for the building process I had to wrap localStorage in a condition because window object is unavailable during build. I wrote return 0 (for pointing the first theme in my themesArray) because otherwise it returns undefined and build fails. Problem is that, in production, by writing it that way I'm unable to retrieve selected theme after refresh. But in dev tools I can see that my theme item is stored with good values. I've got no knowledges about SSR so I feel a bit lost and don't know how to code this. Can someone help?

chalatum
  • 67
  • 1
  • 3
  • 9
  • 1
    SSR is server side rendering, it does not have access to client side storage (session storage, local storage, indexDb, webSql, etc). If you want this information when rendering serverside you have to somehow derive it or send it with your request. – Jacob Smit Aug 08 '20 at 07:33
  • @chalatum did you ever work this out? I'm also using GatsbyJS, and trying to initialise a state hook value with a variable from local storage...but seeing different behaviour in local and the deployed site :( – bluguy Dec 26 '21 at 14:03

1 Answers1

1

I believe your code is correctly setup for SSR and localStorage. This is more a question about triggering rerender with React hooks.

I think this is why it doesn't load your theme:

useEffect(() => {
  localStorage.setItem('theme', JSON.stringify(state.count));
  // no rerender triggered
}, [state.count]); 

You do not change state in useEffect. You need some way to trigger a rerender so you can see the new theme. Trigger a rerender by changing state:

useEffect(() => {
  localStorage.setItem('theme', JSON.stringify(state.count));
  // React rerenders on state change
  setState({
    ...state,
    count: newCount,
  });
}, [state.count]); 

You can pass newCount by pressing a button or however you change your theme.

This question about forcing rerender might help you.

EliteRaceElephant
  • 7,744
  • 4
  • 47
  • 62