Skip to content

Instantly share code, notes, and snippets.

@nanxiaobei
Last active July 14, 2022 08:56
Show Gist options
  • Save nanxiaobei/383f0657e639fb4246332ff8b977b858 to your computer and use it in GitHub Desktop.
Save nanxiaobei/383f0657e639fb4246332ff8b977b858 to your computer and use it in GitHub Desktop.
returns isDark state, and a switch function for dark mode button
const useDarkMode = (): [boolean, () => void] => {
const [isDark, setIsDark] = useState(false);
const setDark = (newDark: boolean) => {
document.documentElement.classList[newDark ? 'add' : 'remove']('dark');
localStorage.setItem('dark', `${newDark}`);
setIsDark(newDark);
};
useEffect(() => {
const darkScheme = window.matchMedia('(prefers-color-scheme: dark)');
// init
setDark(localStorage.getItem('dark') === 'true' || darkScheme.matches);
// listen system
const onChange = (event: MediaQueryListEvent) => {
setDark(event.matches);
};
darkScheme.addEventListener('change', onChange);
return () => {
darkScheme.removeEventListener('change', onChange);
};
}, []);
// manual switch
return [
isDark,
useCallback(() => {
setDark(localStorage.getItem('dark') !== 'true');
}, []),
];
};
export default useDarkMode;
@reorx
Copy link

reorx commented Jun 23, 2022

两次指的是有两个组件分别调用了 useDarkMode,这样 media query 的 listener 就被注册了两次,因而产生一些意料之外的效果。这么想的原因是我感觉这个 hook 应该是可以被多次调用的,一个 app 中有多个地方需要判断和设置 dark mode 也比较常见。

@nanxiaobei
Copy link
Author

嗯有道理,如果两个组件使用,会被注册两次,不过行为应该是一致的,因为系统的 Dark Mode 情况是唯一的。
担心错乱可以设置全局标记,在注册前判断是否已注册。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment