Я пытаюсь добавить переключатель темного режима в приложение Gatsby Js, используя следующий подход:
Используйте API-интерфейс Gatsby wrapRootElement
, чтобы обернуть приложение в провайдер контекста:
// gatsby-browser.js
import ThemeProvider from '@components/themeProvider';
import Layout from '@components/layout';
export const wrapRootElement = data => <ThemeProvider {...data} />;
export const wrapPageElement = data => <Layout {...data} />;
Инициализация темы по умолчанию из localStorage или из настроек браузера пользователя:
// themeProvider.js
const ThemeContext = React.createContext({
darkMode: false,
toggleDarkMode: () => {},
});
const ThemeProvider = ({ element }) => {
const [darkMode, setDarkMode] = useLocalStorage(
'darkMode',
window.matchMedia('(prefers-color-scheme: dark)').matches
);
const toggleDarkMode = () => {
setDarkMode(!darkMode);
};
return (
<ThemeContext.Provider value={{ darkMode, toggleDarkMode }}>
{element}
</ThemeContext.Provider>
);
};
и, наконец, компонент layout
: (обратите внимание на журнал консоли)
// layout.js
const Layout = ({ element }) => (
<ThemeContext.Consumer>
{({ darkMode }) => {
console.log({ darkMode });
return (
<App theme={darkMode ? themes.dark : themes.light}>
{element}
</App>
);
}}
</ThemeContext.Consumer>
);
Это работает отдельно от одной проблемы. При первоначальной загрузке с сохраненным состоянием true
(т. Е. DarkMode включен) приложение отображает светлую тему. Журнал консоли, приведенный выше, отображает правильное значение true
, но приложение не отображает правильную тему.
Если я затем дважды переключаюсь, устанавливая значение темы с true -> false -> true
, тогда darkMode отображается правильно - поэтому logi c работает должным образом, за исключением случаев, когда страница загружается впервые.
Я полагаю, это как-то связано с серверной частью Gatsby, отрисовывающей приложение с состоянием по умолчанию false
, установленным в вызове createContext
в themeProvider.js
но я не уверен, как решить эту проблему.