You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 10:13:19