Actualmente estoy trabajando en un sitio web de pronóstico del tiempo y estoy tratando de aplicar un conmutador de tema. Ya configuré la funcionalidad, pero el tema elegido no persiste cuando se actualiza la página. ¿Alguien podría señalar lo que me estoy perdiendo? El archivo console.log muestra que el tema dentro de localStorage cambia cuando hago clic en el conmutador de tema.
import { WeatherApi } from "./pages/home/weather-api"; import '../src/App.scss' import { createContext, useEffect, useState } from "react"; import ReactSwitch from "react-switch"; export const ThemeContext = createContext({}) function App() { const [theme, setTheme] = useState<string>(localStorage.getItem('theme') || 'light') useEffect(() => { const localTheme = localStorage.getItem(theme) console.log(localTheme) if (!localTheme) { setTheme("light") } if (localTheme) { if (localTheme === 'light') { setTheme('light') localStorage.setItem('theme', theme) console.log(localStorage) } if (localTheme === 'dark') { setTheme('dark') localStorage.setItem('theme', theme) console.log(localStorage) } } },[theme]) const toggleTheme = () => { setTheme((currentTheme: any) => (currentTheme === "light" ? "dark" : "light")) } return ( <ThemeContext.Provider value={{ theme, toggleTheme }}> <div className="App" id={theme}> <WeatherApi /> <div className="switch"> <label>{theme === "light" ? "Light mode" : "Dark mode"}</label> <ReactSwitch onChange={toggleTheme} checked={theme === "dark"} /> </div> </div> </ThemeContext.Provider> ) } export default App;Debe cargar el tema desde localStorage y usarlo como estado inicial, algo como esto:
///... more js code const intialState = localStorage.getItem('theme') || 'light'); const [theme, setTheme] = useState<string>('') const toggleTheme = () => { const newTheme = theme === "light" ? "dark" : "light"; localStorage.setItem('theme', newTheme); setTheme(newTheme); } ///... more js codeNota: no necesita usar JSON.stringify o JSON.parse en cadenas
Ya carga el tema desde localStorage como el valor predeterminado del estado. La otra carga de localStorage en useEffect probablemente esté descartando/anulando los cambios del usuario.
Intenta eliminarlo. Por ejemplo:
useEffect(() => { localStorage.setItem('theme', theme); }, [theme]);Tienes un bucle infinito de gancho de efecto clásico aquí. El gancho de efecto depende del theme . Si llama a setTheme dentro del enlace, se volverá a ejecutar hasta el infinito.
Recomendaría crear un componente de proveedor de contexto de tema como este. Como está utilizando Typescript, debe evitar any y escribir correctamente todos sus valores.
import { createContext, useState, useEffect, FC } from "react"; type Theme = "light" | "dark"; interface ThemeContextValue { theme: Theme; toggleTheme: () => void; } export const ThemeContext = createContext<ThemeContextValue>({ theme: "light", toggleTheme: () => {}, }); export const ThemeContextProvider: FC = ({ children }) => { // initialise state from localStorage const [theme, setTheme] = useState<Theme>( (localStorage.getItem("theme") ?? "light") as Theme ); // update localStorage when the theme changes useEffect(() => { localStorage.setItem("theme", theme); }, [theme]); const toggleTheme = () => { setTheme((current) => (current === "light" ? "dark" : "light")); }; return ( <ThemeContext.Provider value={{ theme, toggleTheme }}> {children} </ThemeContext.Provider> ); };