我刚刚在我的盖茨比网站中集成了一个亮/暗模式切换。我基于Josh Comeau的文章,它在Chrome中工作得很好。然而,在使用Safari的主页上,当我点击切换按钮时,背景颜色不会改变,除非我调整窗口的大小。这是我的gatsby-ssr.js
:
import React from 'react';
import { THEME_COLORS } from 'utils/theme-colors';
import { LOCAL_STORAGE_THEME_KEY } from './src/contexts/ThemeContext';
const SetTheme = () => {
let SetThemeScript = `
(function() {
function getInitialTheme() {
const persistedColorPreference = window.localStorage.getItem('${LOCAL_STORAGE_THEME_KEY}');
const hasPersistedPreference = typeof persistedColorPreference === 'string';
if (hasPersistedPreference) {
return persistedColorPreference;
}
const mql = window.matchMedia('(prefers-color-scheme: dark)');
const hasMediaQueryPreference = typeof mql.matches === 'boolean';
if (hasMediaQueryPreference) {
return mql.matches ? 'dark' : 'light';
}
return 'light';
}
const colorMode = getInitialTheme();
const root = document.documentElement;
root.style.setProperty(
'--color-primary',
colorMode === 'dark'
? '${THEME_COLORS.dark}'
: '${THEME_COLORS.light}'
);
root.style.setProperty(
'--color-secondary',
colorMode === 'dark'
? '${THEME_COLORS.light}'
: '${THEME_COLORS.dark}'
);
root.style.setProperty(
'--color-accent',
colorMode === 'dark'
? '${THEME_COLORS.accentLight}'
: '${THEME_COLORS.accentDark}'
);
root.style.setProperty('--initial-color-mode', colorMode);
})()`;
return <script id="theme-hydration" dangerouslySetInnerHTML={{ __html: SetThemeScript }} />;
};
export const onRenderBody = ({ setPreBodyComponents }) => {
setPreBodyComponents(<SetTheme />);
};
和我的ThemeToggle
分量:
import React, { useContext } from 'react';
import { ThemeContext } from 'contexts/ThemeContext';
import { DarkModeSwitch } from 'react-toggle-dark-mode';
import { THEME_COLORS } from 'utils/theme-colors';
import s from './ThemeToggle.scss';
export const ThemeToggle = () => {
const { theme, toggleTheme } = useContext(ThemeContext);
const toggleDarkMode = (checked: boolean) => {
toggleTheme(checked ? 'dark' : 'light');
};
return (
<div className={s.toggler}>
<DarkModeSwitch
checked={theme === 'dark'}
onChange={toggleDarkMode}
size={20}
sunColor={THEME_COLORS.dark}
moonColor={THEME_COLORS.light}
/>
</div>
);
};
有什么办法解决这个问题吗?
似乎toggleTheme
属性从ThemeContext
值被破坏触发重新渲染,但调整浏览器窗口的大小。Josh通过提供一个带有副作用的setter函数来处理这个问题(它直接操作根样式):
const contextValue = React.useMemo(() => {
function setColorMode(newValue) {
const root = window.document.documentElement;
localStorage.setItem(COLOR_MODE_KEY, newValue);
Object.entries(COLORS).forEach(([name, colorByTheme]) => {
const cssVarName = `--color-${name}`;
root.style.setProperty(cssVarName, colorByTheme[newValue]);
});
rawSetColorMode(newValue);
}
return {
colorMode,
setColorMode,
};
}, [colorMode, rawSetColorMode]);