使用use-dark-mode时,输入框失焦后darkMode.value变为undefined
输入框失焦后@fisch0920/use-dark-mode的value变为undefined问题分析与解决
问题背景
使用Gatsby和React搭建网站,采用@fisch0920/use-dark-mode(use-dark-mode的React兼容分支)实现暗黑模式,CSS定义如下:
body.light-mode { --text-color: var(--text-color-light); } body.dark-mode { --text-color: var(--text-color-dark); }
通过钩子访问darkMode.value,其值应为true或false,但出现异常:点击输入框输入至少一个字符后失焦,darkMode.value会变为undefined。
复现步骤:
- 执行
npm init gatsby初始化新Gatsby项目 - 执行
npm install @fisch0920/use-dark-mode安装兼容包 - 将测试代码复制到
/src/pages/index.js - 打开控制台,点击标题可正常切换模式;输入框输入内容后失焦,控制台打印
darkMode.value: undefined
问题原因
@fisch0920/use-dark-mode分支包的内部实现中,存在对全局focus/blur事件的监听逻辑。当输入框失焦时,会触发其内部状态更新流程,但由于状态同步的bug,导致darkMode.value被意外设置为undefined。该问题属于分支包特有的兼容性问题,与Gatsby的客户端hydration机制结合时更容易触发。
解决方案
方案1:替换为官方use-dark-mode包
放弃该分支版本,直接安装官方维护的包:
npm uninstall @fisch0920/use-dark-mode npm install use-dark-mode
官方版本已修复这类事件监听导致的状态异常问题,API用法与分支版本完全一致,无需大幅修改现有代码。
方案2:自定义简易暗黑模式钩子
如果不想更换第三方包,可以自行封装一个无依赖的暗黑模式钩子,避免第三方包的bug:
import { useState, useEffect } from 'react'; const useDarkMode = (initialState = false) => { const [value, setValue] = useState(() => { // 从localStorage读取初始值,支持页面刷新保留状态 const saved = localStorage.getItem('darkMode'); return saved !== null ? JSON.parse(saved) : initialState; }); useEffect(() => { // 更新body类名,同步暗黑模式状态 document.body.classList.toggle('dark-mode', value); document.body.classList.toggle('light-mode', !value); localStorage.setItem('darkMode', JSON.stringify(value)); }, [value]); // 切换模式的方法 const toggle = () => setValue(prev => !prev); return { value, toggle }; }; export default useDarkMode;
方案3:提升钩子到全局组件
若坚持使用该分支包,将useDarkMode的调用移至Gatsby的根布局组件(src/components/layout.js)中,避免在页面组件中重复实例化钩子,减少状态冲突的概率。
内容的提问来源于stack exchange,提问作者thisisnotworking4meplshelp
相关产品推荐
相关产品推荐

