-
-
Notifications
You must be signed in to change notification settings - Fork 169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The way avoid hydration errors has a negative impact on SEO. #289
Comments
In the end, I implemented theme functionality based on cookies... On every page getServersideProps, 'theme', 'themeSource' cookies must be parsed and passed to DarkModeProvider which used in _app.tsx // context/DarkModeContext.tsx
import {
ReactNode,
createContext,
useCallback,
useEffect,
useMemo,
useState,
} from 'react';
import { setCookie } from 'cookies-next';
import { useMediaQuery } from '@mui/material';
type DarkModeContextType = ReturnType<typeof useDarkMode>;
const DarkModeContext = createContext<DarkModeContextType | undefined>(
undefined,
);
// theme source name
const SYSTEM = 'system' as const;
const CUSTOM = 'custom' as const;
// theme
const LIGHT = 'light' as const;
const DARK = 'dark' as const;
const DEFAULT_THEME = LIGHT;
//cookie name
const THEME = 'theme' as const;
const THEME_SOURCE = 'themeSource' as const;
const useDarkMode = ({
cookieTheme,
cookieThemeSource,
}: {
cookieThemeSource: typeof SYSTEM | typeof CUSTOM | null;
cookieTheme: typeof LIGHT | typeof DARK | null;
}) => {
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
const prefersLightMode = useMediaQuery('(prefers-color-scheme: light)');
const [theme, setTheme] = useState<typeof LIGHT | typeof DARK>(
cookieTheme || DEFAULT_THEME,
);
const [source, setSource] = useState<typeof SYSTEM | typeof CUSTOM>(
cookieThemeSource || CUSTOM,
);
const darkModeActive = useMemo(() => theme === DARK, [theme]);
const autoModeActive = useMemo(() => source === SYSTEM, [source]);
const setValues = useCallback(
({
selectedTheme,
selectedSource,
}: {
selectedTheme: typeof LIGHT | typeof DARK;
selectedSource: typeof SYSTEM | typeof CUSTOM;
}) => {
setCookie(THEME, selectedTheme);
setCookie(THEME_SOURCE, selectedSource);
setTheme(selectedTheme);
setSource(selectedSource);
},
[],
);
const switchToDarkMode = useCallback(() => {
setValues({ selectedTheme: DARK, selectedSource: CUSTOM });
}, [setValues]);
const switchToLightMode = useCallback(() => {
setValues({ selectedTheme: LIGHT, selectedSource: CUSTOM });
}, [setValues]);
const switchToAutoMode = useCallback(() => {
setValues({
selectedTheme: prefersDarkMode ? DARK : LIGHT,
selectedSource: SYSTEM,
});
setTheme(prefersDarkMode ? DARK : LIGHT);
}, [prefersDarkMode, setValues]);
// If there is no value saved in cookies when accessing the website for the first time, set the theme according to the user system settings.
useEffect(() => {
if (cookieThemeSource === null && cookieTheme === null) {
switchToAutoMode();
}
}, [cookieTheme, cookieThemeSource, switchToAutoMode]);
// Change theme when changing system theme settings
useEffect(() => {
if (
source === SYSTEM &&
(prefersDarkMode === true || prefersLightMode === true)
) {
switchToAutoMode();
}
}, [prefersDarkMode, prefersLightMode, source, switchToAutoMode]);
return {
autoModeActive,
darkModeActive,
switchToAutoMode,
switchToDarkMode,
switchToLightMode,
theme,
cookieThemeSource,
};
};
const DarkModeProvider = ({
children,
cookieTheme,
cookieThemeSource,
}: {
cookieThemeSource: typeof SYSTEM | typeof CUSTOM | null;
cookieTheme: typeof LIGHT | typeof DARK | null;
children: ReactNode;
}) => {
const darkModeState = useDarkMode({
cookieTheme,
cookieThemeSource,
});
return (
<DarkModeContext.Provider value={darkModeState}>
{children}
</DarkModeContext.Provider>
);
};
export { DarkModeProvider, DarkModeContext }; |
Simply put, if we use local-storage, there is no way for the current theme to be rendered, before loading the theme from the local-storage on the client. Storing the state in a cookie would work, but as of this library does not support other storage solutions other than local-storage as of now. If we were to allow custom storage solutions (which he have already discussed) this could possible be handled by the library, but as of now, this is out of scope. |
To avoid hydration errors, the example returns null until it is mounted, and this is not an appropriate approach for seo.
Avoid Hydration Mismatch
So, if I have to worry about seo, isn't it appropriate to use this library that uses local storage?
The text was updated successfully, but these errors were encountered: