'Material UI theme not updating with Next.js
I am trying to implement a dark mode button with Material UI and Next.js. I want it to save the value to local storage and when I refresh, it must show the correct value. I have the following theme provider:
import { createContext, useEffect, useMemo, useState } from 'react';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import useLocalStorage from 'app-hooks/local-storage';
export const ThemeContext = createContext({
toggleColorMode: () => {},
mode: 'light',
});
const Theme = ({ children }) => {
const [mode, setMode] = useLocalStorage('mode', 'light');
const [theme, setTheme] = useState(() =>
createTheme({
palette: {
mode,
},
})
);
const themeContextValue = useMemo(
() => ({
toggleColorMode: () => {
setMode((prevMode) => (prevMode === 'light' ? 'dark' : 'light'));
},
mode,
}),
[mode, setMode]
);
// useEffect(() => {
// setTheme(
// createTheme({
// palette: {
// mode,
// },
// })
// );
// }, [mode]);
console.log(theme);
return (
<ThemeContext.Provider value={themeContextValue}>
<ThemeProvider theme={theme}>{children}</ThemeProvider>
</ThemeContext.Provider>
);
};
export default Theme;
The console.log statement when I refresh the page shows "light" on the server side and "dark" on the client side.
This is the code of the custom useLocalStorage hook.
import { useCallback, useEffect, useState } from 'react';
const useLocalStorage = (key, initialValue) => {
const initialize = useCallback(() => {
if (typeof window === 'undefined') {
return initialValue;
}
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.log(error);
return initialValue;
}
}, [initialValue, key]);
const [storedValue, setStoredValue] = useState(initialize());
const setValue = (value) => {
try {
const valueToStore =
value instanceof Function ? value(storedValue) : value;
if (typeof window !== 'undefined') {
window.localStorage.setItem(key, JSON.stringify(valueToStore));
}
setStoredValue(valueToStore);
} catch (error) {
console.log(error);
}
};
useEffect(() => {
setStoredValue(initialize());
}, [initialize]);
return [storedValue, setValue];
};
export default useLocalStorage;
If I uncomment the code of the useEffect, the console.log triggers two times with the correct theme.palette.mode value ("dark"), but visually the components are still shown as if it was light.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
