How can i save choosen theme in LocalStorage with React Context?

I want to create dark light mode using context. Everything is normal, I just can’t save to local storage. When you switch to dark mode and refresh, dark mode, but when you switch to light mode and refresh, it returns to dark mode. How can I solve this problem? The function works normally, the only problem was related to local, which when switching to light mode, dark mode is visible again .

import { createContext, useEffect, useState } from "react";


export const ThemeContext = createContext()

export const ThemeContextProvider = ({ children }) => {

    const [darkMode, setDarkMode] = useState(localStorage.getItem('Mode') ? localStorage.getItem('Mode') : false)

    const changeTheme = () => {
        setDarkMode(!darkMode)
    }

    useEffect(() => {
        localStorage.setItem('Mode', darkMode)
    }, [darkMode])

    return (
        <ThemeContext.Provider value={{ darkMode, changeTheme }}>
            {children}
        </ThemeContext.Provider>
    )
}

import React, { useContext } from 'react'
import { NavLink } from 'react-router-dom'
import { ThemeContext } from '../context/ThemeContext'
import { BiMoon } from "react-icons/bi"
import { BsSun } from "react-icons/bs"
const Header = () => {
    const { darkMode, changeTheme } = useContext(ThemeContext)
    return (
        <>
            <nav className="navbar navbar-expand-lg bg-dark navbar-dark">
                <div className="container-fluid">
                    <a className="navbar-brand" href="#">Navbar</a>
                    <button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
                        <span className="navbar-toggler-icon" />
                    </button>
                    <div className="collapse navbar-collapse" id="navbarNav">
                        <ul className="navbar-nav">
                            <li className="nav-item">
                                <NavLink className="nav-link active" to='/'>Home</NavLink>
                            </li>
                            <li className="nav-item">
                                <NavLink className="nav-link" to='/about'>About</NavLink>
                            </li>
                            <li className="nav-item">
                                <button onClick={changeTheme}>
                                    {darkMode ? <BsSun /> : <BiMoon />}
                                    changeTheme
                                </button>
                            </li>
                        </ul>
                    </div>
                </div>
            </nav>
        </>
    )
}

export default Header


import React from 'react'
import { BrowserRouter, Route, Routes } from 'react-router-dom'
import Home from "../pages/Home"
import About from "../pages/About"
import Header from '../components/Header'
import { ContextProvider } from "../context/GlobalState"
import { useContext } from 'react'
import { ThemeContext } from '../context/ThemeContext'
const AppRouter = () => {
    const { darkMode } = useContext(ThemeContext)
    return (
        <>
            <main className={darkMode ? 'dark' : 'light'}>
                <ContextProvider>
                    <BrowserRouter>
                        <Header />
                        <Routes>
                            <Route path='/' element={<Home />} />
                            <Route path='/about' element={<About />} />
                        </Routes>
                    </BrowserRouter>
                </ContextProvider>
            </main>


        </>
    )
}

export default AppRouter

>Solution :

The function localStorage.get always returns a string. Strings are always truthy. Consider this example:

localStorage.setItem("test", false);
if (localStorage.getItem("test")) {
    console.log("This always prints since the string \"false\" is considered truthy");
}

To fix your issue imply use JSON.parse:

const [darkMode, setDarkMode] = useState(localStorage.getItem('Mode') ? JSON.parse(localStorage.getItem('Mode')) : false)

Complete example, including getting rid of the useless use effect:

// Use the ?? operator to make it a bit shorter
const [darkMode, setDarkMode] = useState(
    JSON.parse(localStorage.getItem("mode")??"false")
);

// pass a callback to `setDarkMode` to avoid race conditions
const changeTheme = () => setDarkMode(darkMode=>{
        localStorage.setItem("Mode", !darkMode);
        return !darkMode;
}

Leave a Reply