我的网站有一个明暗主题。默认主题为light
。如果用户将主题更改为dark
,则将主题保存到localStorage
。
在组件树根的下一次访问/刷新时,此代码运行:
useLayoutEffect(() => {
let storedTheme = localStorage.getItem("theme");
if (storedTheme === "light" || storedTheme === "dark") {
// Redux action. Other components subscribe to the theme.
setTheme(storedTheme);
}
}, [setTheme]);
假设用户选择深色主题作为他们的偏好。它工作正常。但是,第一个渲染将是灯光主题。第二个渲染将是深色主题。当访问该站点时,这会导致灯光暗闪烁。
有没有办法确保我的第一个渲染的设定值为localStorage
?
将数据保存到我的第一个渲染中的工作是初始化redux存储,如下所示:
if (typeof localStorage != "undefined") {
initialState = {
theme: localStorage.getItem("theme"),
};
} else {
initialState = {};
}
const store = createStore(reducers, initialState);
但这使情况变得更糟,因为在第一次加载时就不再重新渲染组件,因为theme
来自redux 的prop从未更改过,因为商店是使用用户首选项初始化的。所以我回到上面的原始问题中的旧方法。
之所以会发生闪烁,是因为我使用Javascript控制我的react应用程序中的主题。我还使用Gatsby,它会生成我网站的静态版本,该网站会在我的react应用之前加载。
加载网站是这样的:
例如,具有深色主题首选项的用户访问。他们看到静态内容而没有任何Javascript,而JS捆绑包则在后台下载。
由于light主题是默认主题,因此网站的静态版本将是light。
Javascript加载,React的第一个渲染发生,并且Redux存储被初始化。根组件从中获取主题,localStorage
树以深色主题重新渲染。
由于2到3之间的事件而发生闪烁。
我没有完全解决问题。但是,通过启用Gatsby的服务人员,我设法减轻了闪烁现象,使其更加不明显。Worker缓存Javascript捆绑包供下次访问,而从磁盘加载Javascript意味着闪烁将持续较短的时间,因为JS捆绑包已经可以执行了。