Tengo un estado que almacena el tema de la aplicación actual, ya sea oscuro o claro. Utilizo el enlace useEffect para almacenar los cambios de estado en localStorage de modo que cuando el usuario actualice la página, se guarde su tema preferido y otro enlace useEffect para actualizar mi estado durante la carga inicial. Sin embargo, mi estado no se actualiza durante esa carga inicial.
Cosas que he probado:
A continuación se muestran mis códigos:
const [theme, setTheme] = useState({}); useEffect(() => { const loadedTheme = JSON.parse(localStorage.getItem(themeStorage)) if (loadedTheme) { console.log("Initial load") console.log(loadedTheme); console.log("Setting theme to localStorage") Promise.resolve() .then(() => { setTheme({ dark: loadedTheme.dark }) }) .then(() => { console.log(theme) }) .then(() => changeTheme()) } }, []) useEffect(() => { localStorage.setItem(themeStorage, JSON.stringify(theme)) console.log("Inside useEffect to save changed theme") console.log(theme) }, [theme]) function changeTheme() { console.log("Inside changeTheme function"); console.log(theme); if (!theme || !theme.dark) { //light turns to dark for (let vars of Object.keys(varTheme)) { document.documentElement.style.setProperty(`--${vars}`, varTheme[vars][0]); } setTheme({ ...theme, dark: true }) } else { for (let vars of Object.keys(varTheme)) { //dark turns to light document.documentElement.style.setProperty(`--${vars}`, varTheme[vars][1]); } setTheme({ ...theme, dark: false }) } }No está un poco claro cuál cree que es el problema, pero sospecho que está viendo/describiendo que el theme no se actualiza en el primer gancho useEffect .
La razón de esto es que el estado React se considera constante e inmutable. Dentro de la devolución de llamada useEffect , el valor del estado del theme se cierra en el alcance de la devolución de llamada y, sin importar la espera o el encadenamiento de promesas, cambiará el valor del estado cerrado en el alcance.
const [theme, setTheme] = useState({}); // <-- initial state useEffect(() => { const loadedTheme = JSON.parse(localStorage.getItem(themeStorage)) if (loadedTheme) { console.log("Initial load") console.log(loadedTheme); console.log("Setting theme to localStorage") Promise.resolve() .then(() => { setTheme({ dark: loadedTheme.dark }) }) .then(() => { console.log(theme) }) // <-- still initial state .then(() => changeTheme()) } }, []); // <-- mounting "instance" of state Luego invoque changeTheme que desde el gabinete y también accederá al estado "obsoleto" del gabinete.
LocalStorage es síncrono, por lo que puede configurar su estado inicial con una función de inicialización.
const loadThemeFromStorage = () => { const { dark } = JSON.parse(localStorage.getItem(themeStorage)) ?? {}; return { dark }; }; const [theme, setTheme] = useState(loadThemeFromStorage()); Ahora, con el estado ya establecido inicialmente, puede llamar de forma segura a changeTheme en el gancho de montaje useEffect .
useEffect(() => { console.log("Initial load"); console.log(theme); changeTheme(); }, []); useEffect(() => { localStorage.setItem(themeStorage, JSON.stringify(theme)); console.log("Inside useEffect to save changed theme"); console.log(theme); }, [theme]);