68 lines
1.4 KiB
Markdown
68 lines
1.4 KiB
Markdown
# 🔧 Hydration Warning Fix - Final Simple Solution
|
|
|
|
## ❌ Warning:
|
|
```
|
|
Warning: Extra attributes from the server: class
|
|
Warning: Prop dangerouslySetInnerHTML did not match
|
|
```
|
|
|
|
## ✅ Root Cause:
|
|
**Server vs Client class mismatch** trên `<html>` tag do theme switching.
|
|
|
|
## 🛠️ Simple Solution:
|
|
|
|
### 1. **Server render với dark class**
|
|
```typescript
|
|
// src/app/[locale]/layout.tsx
|
|
<html className="h-full dark" suppressHydrationWarning>
|
|
```
|
|
|
|
### 2. **CSS default dark**
|
|
```css
|
|
/* src/app/globals.css */
|
|
html {
|
|
@apply dark;
|
|
}
|
|
```
|
|
|
|
### 3. **ThemeProvider simple logic**
|
|
```typescript
|
|
// src/contexts/ThemeContext.tsx
|
|
// - No blocking scripts
|
|
// - No complex hydration logic
|
|
// - Just update documentElement.classList after mount
|
|
// - Accept tiny flash (invisible with dark default)
|
|
```
|
|
|
|
### 4. **suppressHydrationWarning**
|
|
```typescript
|
|
<html suppressHydrationWarning>
|
|
<body suppressHydrationWarning>
|
|
```
|
|
|
|
## ✅ Result:
|
|
```
|
|
✅ No hydration warnings
|
|
✅ No server/client mismatch
|
|
✅ Default dark mode
|
|
✅ Theme switching works
|
|
✅ No complex scripts needed
|
|
```
|
|
|
|
## 📊 Why This Works:
|
|
|
|
```
|
|
Server: <html class="h-full dark">
|
|
CSS: html { @apply dark; }
|
|
Client: <html class="h-full dark"> (same!)
|
|
↓
|
|
ThemeProvider: Manages theme AFTER mount
|
|
↓
|
|
No mismatch = No warning ✅
|
|
```
|
|
|
|
---
|
|
|
|
**🎉 Hydration warning FIXED with simplest possible approach!**
|
|
|