QwikJS主题值持久化问题:首次加载浏览器端代码不执行
明暗主题切换首次加载逻辑不执行的问题
我在实现明暗主题切换时,遇到了首次加载时浏览器端的主题恢复逻辑不执行的问题,相关代码如下:
useTask$(({ track }) => { track(() => themeAppearance.value); if (isBrowser) { const savedTheme = localStorage.getItem("themeApp"); console.log("from local storage", savedTheme); if (savedTheme) { themeAppearance.value = savedTheme === "dark" ? ThemeTypes.Dark : ThemeTypes.Ligth; return; } } });
只有通过按钮调用useThemeHook中的toggleAppearance$函数切换themeAppearance时,相关逻辑才正常工作,该函数代码如下:
const toggleAppearance$ = $(() => { console.log(themeAppearance.value); if (themeAppearance.value === ThemeTypes.Dark) { themeAppearance.value = ThemeTypes.Ligth; backGroundPrimaryColor.value = BackdrounColor.Ligth; backGroundSecondaryColor.value = BackdrounColor.Ligth; textColorPrimary.value = TextColor.HardTextLigthBackground; textColorSecondary.value = TextColor.LigthTextLigthBackground; localStorage.setItem("themeApp", ThemeTypes.Ligth); return; } if ( themeAppearance.value === ThemeTypes.Ligth && panelBackground === "solid" ) { themeAppearance.value = ThemeTypes.Dark; backGroundPrimaryColor.value = BackdrounColor.DarkPrimarySolid; backGroundSecondaryColor.value = BackdrounColor.DarkSecondarySolid; textColorPrimary.value = TextColor.HardTextDarkBackground; textColorSecondary.value = TextColor.LigthTextDarkBackground; localStorage.setItem("themeApp", ThemeTypes.Dark); return; } if ( themeAppearance.value === ThemeTypes.Ligth && panelBackground === "translucent" ) { themeAppearance.value = ThemeTypes.Dark; backGroundPrimaryColor.value = BackdrounColor.DarkPrimaryTranslucent; backGroundSecondaryColor.value = BackdrounColor.DarkSecondaryTranslucent; textColorPrimary.value = TextColor.HardTextDarkBackground; textColorSecondary.value = TextColor.LigthTextDarkBackground; localStorage.setItem("themeApp", ThemeTypes.Dark); return; } });
我试过用useVisibleTask$,但它会在首次渲染后才执行,导致先显示默认深色主题再切换为保存的浅色主题,用户体验很差。
解决方案
1. 问题根源
useTask$默认在服务端和客户端都执行,且你通过track(() => themeAppearance.value)设置了仅当themeAppearance变化时触发任务,首次加载时themeAppearance无变动,任务不会主动执行。而useVisibleTask$延迟到组件可见后执行,必然会出现主题闪烁。
2. 核心修复:初始化阶段同步读取本地存储
直接在状态初始化时读取localStorage并设置对应主题,让框架在首次渲染前就拿到正确的主题状态,彻底避免闪烁:
// 初始化主题状态时直接读取本地存储 const themeAppearance = useSignal(() => { if (isBrowser) { const savedTheme = localStorage.getItem("themeApp"); return savedTheme === "dark" ? ThemeTypes.Dark : ThemeTypes.Ligth; } // 服务端默认值,可按需调整 return ThemeTypes.Dark; }); // 同步初始化颜色状态,确保和主题匹配 const backGroundPrimaryColor = useSignal(() => { if (isBrowser) { const savedTheme = localStorage.getItem("themeApp"); if (savedTheme === "dark") { return panelBackground === "solid" ? BackdrounColor.DarkPrimarySolid : BackdrounColor.DarkPrimaryTranslucent; } return BackdrounColor.Ligth; } return BackdrounColor.DarkPrimarySolid; }); const backGroundSecondaryColor = useSignal(() => { if (isBrowser) { const savedTheme = localStorage.getItem("themeApp"); if (savedTheme === "dark") { return panelBackground === "solid" ? BackdrounColor.DarkSecondarySolid : BackdrounColor.DarkSecondaryTranslucent; } return BackdrounColor.Ligth; } return BackdrounColor.DarkSecondarySolid; }); const textColorPrimary = useSignal(() => { if (isBrowser) { const savedTheme = localStorage.getItem("themeApp"); return savedTheme === "dark" ? TextColor.HardTextDarkBackground : TextColor.HardTextLigthBackground; } return TextColor.HardTextDarkBackground; }); const textColorSecondary = useSignal(() => { if (isBrowser) { const savedTheme = localStorage.getItem("themeApp"); return savedTheme === "dark" ? TextColor.LigthTextDarkBackground : TextColor.LigthTextLigthBackground; } return TextColor.LigthTextDarkBackground; });
3. 可选:提前通过原生脚本设置CSS类
如果你的主题通过CSS类控制,可以在页面head中插入一段原生脚本,在DOM渲染前就设置主题类,进一步消除闪烁可能:
<script> if (typeof localStorage !== 'undefined') { const savedTheme = localStorage.getItem('themeApp'); document.documentElement.classList.toggle('dark-theme', savedTheme === 'dark'); } </script>
这段脚本会在框架初始化前执行,确保浏览器第一时间应用正确的主题样式。
内容的提问来源于stack exchange,提问作者rodrigo lemus
相关产品推荐
相关产品推荐

