Skip to content

Commit 818d2ea

Browse files
committed
fix(ui): correct dark mode initialization to avoid setState in effect
1 parent 2b1cd6d commit 818d2ea

File tree

1 file changed

+20
-19
lines changed

1 file changed

+20
-19
lines changed

src/components/shared/DarkModeToggle.tsx

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,29 @@ import { Moon, Sun } from 'lucide-react';
44
const DarkModeToggle = () => {
55
// Initialize from the class that was already set in index.html
66
const [isDarkMode, setIsDarkMode] = useState(() => {
7-
return document.documentElement.classList.contains('dark');
7+
const storedTheme = localStorage.getItem('theme');
8+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
9+
return storedTheme === 'dark' || (!storedTheme && prefersDark);
810
});
9-
const [isHovered, setIsHovered] = useState(false);
1011

1112
useEffect(() => {
12-
const theme = localStorage.getItem('theme');
13-
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
14-
15-
// ✅ Determine the final theme first
16-
let shouldBeDark =
17-
theme === 'dark' || (!theme && prefersDark);
18-
19-
// ✅ Apply class WITHOUT calling setState inside effect yet
20-
if (shouldBeDark) {
21-
document.documentElement.classList.add('dark');
22-
} else {
23-
document.documentElement.classList.remove('dark');
24-
}
25-
26-
// ✅ Update state ONCE at the end
27-
setIsDarkMode(shouldBeDark);
28-
13+
// Listen for system theme changes (only if no manual preference is set)
14+
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
15+
const handleThemeChange = (e: MediaQueryListEvent) => {
16+
// Only update if user hasn't set a manual preference
17+
if (!localStorage.getItem('theme')) {
18+
const shouldBeDark = e.matches;
19+
if (shouldBeDark) {
20+
document.documentElement.classList.add('dark');
21+
} else {
22+
document.documentElement.classList.remove('dark');
23+
}
24+
setIsDarkMode(shouldBeDark);
25+
}
26+
};
27+
28+
mediaQuery.addEventListener('change', handleThemeChange);
29+
return () => mediaQuery.removeEventListener('change', handleThemeChange);
2930
}, []);
3031

3132
const toggleDarkMode = () => {

0 commit comments

Comments
 (0)