useDarkMode

具有自动数据持久性的深色模式。

⚠️ v6.1.0 破坏性变更

存储格式已从布尔值更改为字符串值。 如果你正在从旧版本升级:

  • 旧格式: true/false 布尔值
  • 新格式: "dark"/"light" 字符串值
  • 自动迁移: 现有数据将自动迁移
  • SSR 脚本: 需要更新以处理字符串比较
迁移指南

如果你有自定义的 SSR 脚本,请按照下面示例中的方式进行更新。库会自动处理数据迁移,但你的自定义脚本需要在过渡期间处理新旧两种格式。

Tips

点击展开 对于服务端渲染的应用程序而言,由于无法在服务端获取到用户的颜色偏好。所以第一次渲染的时候可能会出现闪烁。想要避免此问题,你可以参考一下步骤。

  1. 在你的内容渲染前增加一个脚本。
<script
  dangerouslySetInnerHTML={{
    // 增加一个自执行的函数
    __html: `
          (function () {
            function setDark(dark) {
              dark &&  document.documentElement.classList.add('dark');
            }
            let store = localStorage.getItem('reactuses-color-scheme');
            let dark;
            if(store === null){
              const darkQuery = window.matchMedia('(prefers-color-scheme: dark)');
              dark = darkQuery.matches;
            }else {
              // 处理向后兼容性:将旧的布尔值转换为字符串
              if (store === 'true' || store === 'false') {
                const boolValue = store === 'true';
                const stringValue = boolValue ? 'dark' : 'light';
                localStorage.setItem('reactuses-color-scheme', stringValue);
                dark = boolValue;
              } else {
                // 直接处理字符串值 ('dark' 或 'light')
                dark = store === 'dark';
              }
            }
            setDark(dark)
          })();
      `,
  }}
></script>
  1. 为了方便统一管理主题颜色,我们推荐使用 context 来存储它们。
import { useDarkMode } from "@reactuses/core";
import React, { createContext, useContext } from "react";

type ThemeContext = { theme: boolean; toggleTheme: () => void };

const ThemeContext = createContext<ThemeContext | undefined>(undefined);

export function ThemeProvider({ children }: { children: React.ReactNode }) {
  const [dark, toggle] = useDarkMode({
    classNameDark: "dark",
    classNameLight: "light",
    defaultValue: false,
  });

  return (
    <ThemeContext.Provider value={{ theme: !!dark, toggleTheme: toggle }}>
      {children}
    </ThemeContext.Provider>
  );
}

export function useTheme() {
  const context = useContext(ThemeContext);
  if (context === undefined) {
    throw new Error("useTheme must be used within a ThemeProvider");
  }
  return context;
}

useDarkMode 提供简单的深色/浅色模式切换,并自动持久化到 localStorage。它返回一个包含当前主题状态和切换函数的元组。该 hook 将 CSS 类名(可配置为 classNameDarkclassNameLight)应用到 <html> 元素,并在没有存储值时通过 prefers-color-scheme 媒体查询与用户的系统偏好同步。它以系统偏好为默认值,但允许用户覆盖。

使用场景

  • 为应用添加带有自动持久化功能的深色模式切换
  • 构建以用户系统颜色方案偏好为默认值的主题切换器
  • 将深色/浅色 CSS 类应用到根元素,实现 CSS 驱动的主题切换

注意事项

  • SSR 安全:在服务端渲染期间深色模式状态返回 false。服务端不会访问 DOM 或 localStorage。参见下方”技巧”部分了解如何防止未样式化内容的闪烁。
  • 持久化:将偏好存储在 localStorage 中,键名为 "reactuses-color-scheme"。存储的值会在 v6.1.0+ 中自动从旧的布尔格式迁移到新的字符串格式。
  • 相关 hooks:如需超越深色/浅色的多主题支持,参见 useColorMode。如需检测系统偏好但不进行持久化,参见 usePreferredDarkusePreferredColorScheme

Usage

Live Editor

function Demo() {
  const [theme, toggleDark] = useDarkMode({
    classNameDark: "dark",
    classNameLight: "light",
    defaultValue: false,
  });

  return (
    <div>
      <div>主题: {theme ? "深色" : "浅色"}</div>
      <br />
      <div>
        <button onClick={toggleDark}>切换深色模式</button>
      </div>
    </div>
  );
};
Result

API

UseDarkOptions

参数名描述类型默认值
selector适用于目标元素的 CSS 选择器string'html'
attribute应用到目标元素的 html 属性string'class'
defaultValue默认值booleanfalse
storageKey将数据持久保存到 localStorage/sessionStorage 的键值string'reactuses-color-scheme'
storage存储对象,可以是localStorage或sessionStorage() => StoragelocalStorage
classNameDark应用到目标元素上黑色类名称string (必填)-
classNameLight应用到目标元素上的亮色类名称string (必填)-

useDarkMode

Returns

readonly [boolean | null, () => void, React.Dispatch<React.SetStateAction<boolean | null>>]: 包含以下元素的元组:

  • 黑暗状态的当前值。
  • 切换黑暗状态的功能。
  • 更新黑暗状态的功能。

Arguments

参数名描述类型默认值
options-UseDarkOptions (必填)-