Skip to content

Commit f00cbbe

Browse files
committed
chore(theme): fix hydration problem
1 parent b1a4516 commit f00cbbe

1 file changed

Lines changed: 40 additions & 28 deletions

File tree

src/lib/theme/ThemeProvider.tsx

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import React, { createContext, useContext, ReactNode, useState, useEffect, useCallback } from 'react'
3+
import React, { createContext, useContext, ReactNode, useState, useEffect, useCallback, useMemo } from 'react'
44
import { NETWORK_COLORS, SEMANTIC_COLORS, ELEVATION_LEVELS } from './themeConstants'
55

66
interface ThemeContextType {
@@ -33,12 +33,14 @@ interface ThemeProviderProps {
3333
}
3434

3535
export function ThemeProvider({ children, initialNetworkId = 'polkadot' }: ThemeProviderProps) {
36-
const [isDarkTheme, setIsDarkTheme] = useState<boolean>(true);
36+
const [isDarkTheme, setIsDarkTheme] = useState<boolean>(false);
3737
const [isLoaded, setIsLoaded] = useState<boolean>(false);
3838
const [currentNetworkId, setCurrentNetworkId] = useState<string>(initialNetworkId);
39+
const [mounted, setMounted] = useState(false);
3940

40-
4141
const applyTheme = useCallback((isDark: boolean, networkId: string) => {
42+
if (typeof window === 'undefined') return;
43+
4244
document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
4345
document.documentElement.setAttribute('data-network', networkId);
4446

@@ -59,9 +61,8 @@ export function ThemeProvider({ children, initialNetworkId = 'polkadot' }: Theme
5961
});
6062
}, []);
6163

62-
6364
useEffect(() => {
64-
if (typeof window === 'undefined') return;
65+
setMounted(true);
6566

6667
const storedTheme = localStorage.getItem('theme');
6768
const storedNetwork = localStorage.getItem('currentNetwork');
@@ -71,19 +72,17 @@ export function ThemeProvider({ children, initialNetworkId = 'polkadot' }: Theme
7172
setCurrentNetworkId(storedNetwork);
7273
}
7374

75+
let isDark: boolean;
7476
if (storedTheme) {
75-
const isDark = storedTheme === 'dark';
76-
setIsDarkTheme(isDark);
77-
applyTheme(isDark, networkToUse);
77+
isDark = storedTheme === 'dark';
7878
} else {
79-
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
80-
setIsDarkTheme(prefersDark);
81-
applyTheme(prefersDark, networkToUse);
79+
isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
8280
}
8381

82+
setIsDarkTheme(isDark);
83+
applyTheme(isDark, networkToUse);
8484
setIsLoaded(true);
8585

86-
8786
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
8887
const handleChange = (e: MediaQueryListEvent) => {
8988
if (!localStorage.getItem('theme')) {
@@ -94,25 +93,22 @@ export function ThemeProvider({ children, initialNetworkId = 'polkadot' }: Theme
9493

9594
mediaQuery.addEventListener('change', handleChange);
9695
return () => mediaQuery.removeEventListener('change', handleChange);
97-
}, [currentNetworkId, applyTheme]);
96+
}, [applyTheme, currentNetworkId]);
9897

99-
10098
useEffect(() => {
101-
if (isLoaded) {
99+
if (isLoaded && mounted) {
102100
applyTheme(isDarkTheme, currentNetworkId);
103101
localStorage.setItem('currentNetwork', currentNetworkId);
104102
}
105-
}, [currentNetworkId, isLoaded, isDarkTheme, applyTheme]);
103+
}, [currentNetworkId, isLoaded, isDarkTheme, applyTheme, mounted]);
106104

107-
108105
const toggleTheme = useCallback(() => {
109106
const newIsDark = !isDarkTheme;
110107
setIsDarkTheme(newIsDark);
111108
applyTheme(newIsDark, currentNetworkId);
112109
localStorage.setItem('theme', newIsDark ? 'dark' : 'light');
113110
}, [isDarkTheme, currentNetworkId, applyTheme]);
114111

115-
116112
const getNetworkColor = useCallback((colorType: 'primary' | 'secondary' | 'light' | 'dark'): string => {
117113
const networkColors = NETWORK_COLORS[currentNetworkId] || NETWORK_COLORS['polkadot'];
118114
return networkColors[colorType];
@@ -130,17 +126,33 @@ export function ThemeProvider({ children, initialNetworkId = 'polkadot' }: Theme
130126
return isDarkTheme ? elevationValue.dark : elevationValue.light;
131127
}, [isDarkTheme]);
132128

129+
const contextValue = useMemo(() => ({
130+
isDarkTheme,
131+
toggleTheme,
132+
isLoaded,
133+
currentNetworkId,
134+
setCurrentNetworkId,
135+
getNetworkColor,
136+
getColor,
137+
getElevation
138+
}), [
139+
isDarkTheme,
140+
toggleTheme,
141+
isLoaded,
142+
currentNetworkId,
143+
setCurrentNetworkId,
144+
getNetworkColor,
145+
getColor,
146+
getElevation
147+
]);
148+
149+
150+
if (!mounted) {
151+
return null;
152+
}
153+
133154
return (
134-
<ThemeContext.Provider value={{
135-
isDarkTheme,
136-
toggleTheme,
137-
isLoaded,
138-
currentNetworkId,
139-
setCurrentNetworkId,
140-
getNetworkColor,
141-
getColor,
142-
getElevation
143-
}}>
155+
<ThemeContext.Provider value={contextValue}>
144156
{children}
145157
</ThemeContext.Provider>
146158
);

0 commit comments

Comments
 (0)