Search code examples
javascriptreactjstailwind-cssdarkmode

Persist user theme in localStorage on reload


I am building a weather app with React & Tailwind & I am trying to save the users theme preference to local storage but it isn't persisting on reload

Here's my code. I don't know what I am doing wrong. I can set it switching in the storage panel in dev tools and it is saving it there but it isn't setting it to the correct theme on page reload.

function App() {
  const [darkMode, setDarkMode] = useState(false);

  //Call from local Storage
  useEffect(() => {
    const storedPreference = localStorage.getItem('prefersDarkMode');
    if (storedPreference) {
      setDarkMode(JSON.parse(storedPreference));
    }
  }, []);

  //Set to Local Storage
  useEffect(() => {
    if (darkMode) {
      localStorage.setItem('prefersDarkMode', 'true');
      document.body.classList.add('dark');
    } else {
      localStorage.setItem('prefersDarkMode', 'false');
      document.body.classList.remove('dark');
    }
  }, [darkMode]);
  return (
    <div className={darkMode ? 'flex flex-col min-h-screen bg-gray-800' : 'bg-neutral-50 flex flex-col min-h-screen'}>
      <Header>
        <button
          onClick={() => {
            setDarkMode(!darkMode);
          }}
        >
          {darkMode ? <BsFillSunFill className="fill-neutral-100 text-2xl" /> : <BsFillMoonFill className="fill-gray-700 text-2xl" />}
        </button>
      </Header>
      <ToastContainer theme={darkMode ? 'dark' : 'light'} />
      <Footer />
    </div>
  );
}

export default App;


Solution

  • The problem I have seen in your codes is ..

    the other useEffect initially calls the localStorage for prefersDarkMode

    and the other one is for changing the darkmode state and setting the localStorage

    when you reload the page, the darkmode state is always false, because of this

    useEffect(() => {
      if (darkMode) {
        localStorage.setItem('prefersDarkMode', 'true');
        document.body.classList.add('dark');
      } else {
        localStorage.setItem('prefersDarkMode', 'false');
        document.body.classList.remove('dark');
      }
    }, [darkMode]);
    

    this useEffect will set the prefersDarkMode in your localStorage to false every time you reload

    to fix this, i added another state to check if the app already call the localStorage

    const [flag, setFlag] = useState(false);
    
     //Call from local Storage
     useEffect(() => {
       const storedPreference = localStorage.getItem("prefersDarkMode");
       if (storedPreference) {
         setDarkMode(JSON.parse(storedPreference));
       }
       setFlag(true);
     }, []);
    
     //Set to Local Storage
     useEffect(() => {
       if (flag) {
         localStorage.setItem("prefersDarkMode", darkMode);
         document.body.classList.toggle('dark',darkMode)
       }
     }, [darkMode, flag]);
    

    so that, it won't set it back to default on reload

    here is the working example https://codesandbox.io/s/goofy-nash-6fu3c5