1

I am using react to switch between light and dark mode in my website . I also want the theme to persist using localstorage . The problem is that while clicking on switch to toggle the theme the corresponding localstorage theme value does not update. I know that state updates are asynchronous but I want to fix this .

My code:

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

  //change theme 
  const toggleTheme = ()=>{ 

    setDarkMode(!darkMode);
    const root = window.document.documentElement;
    if(localStorage.getItem("isDark")=== null){
      localStorage.setItem("isDark",darkMode);
    }else{
      localStorage.setItem("isDark",darkMode);
    }
    root.classList.toggle('dark');

  }

I tried using async await but the result was the same .

tahsin_siad
  • 86
  • 1
  • 11
vasilis 123
  • 585
  • 1
  • 12
  • 26
  • Duplicate: [Why calling react setState method doesn't mutate the state immediately?](https://stackoverflow.com/questions/30782948/why-calling-react-setstate-method-doesnt-mutate-the-state-immediately) –  Apr 02 '21 at 09:08
  • 2
    Solution: `const newValue = !darkMode;` and `setDarkMode(newValue);` and `localStorage.setItem("isDark", newValue);` –  Apr 02 '21 at 09:09
  • As a side note, your `if... else...` conditional does not make sense as you are going to do `localStorage.setItem("isDark",darkMode);` regardless of the condition – secan Apr 02 '21 at 09:10

2 Answers2

2

You can use useEffect in order to keep watch on darkMode.

Here, useEffect will be called every time when darkMode value is updated. Hence, setting the localStorage value inside. And I removed if.. else.. condition as I guess there is no need of that, if you feel you can keep it.

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

useEffect(() => {
  localStorage.setItem("isDark", darkMode);
}, darkMode);
 
// change theme 
const toggleTheme = ()=>{ 
  setDarkMode(!darkMode);
  const root = window.document.documentElement;
  root.classList.toggle('dark');
}
Surjeet Bhadauriya
  • 6,755
  • 3
  • 34
  • 52
1

You can't use state variable darkMode just after updating it via setDarkMode due to its async nature. You could use useEffect hook but that wont be the best way imo just to solve a simple problem like this. Instead you can use it this way

// Initialize variable from localstorage value
const [darkMode, setDarkMode] = useState(
  () => JSON.parse(localStorage.getItem("isDark")) ?? false
);

//change theme
const toggleTheme = () => {
  const updatedDarkMode = !darkMode;

  setDarkMode(updatedDarkMode);
  const root = window.document.documentElement;
  localStorage.setItem("isDark", updatedDarkMode);

  root.classList.toggle("dark");
};
Rishabh Singh
  • 353
  • 2
  • 8