#10 bug: React hydration error with useLocalStorage hook

Закриті
3 місяців тому відкрито fszontagh · 1 коментарів
Szontágh Ferenc відкоментовано 3 місяців тому

React hydration error occurs on page load:

Uncaught Error: Minified React error #418

Error Details: React error #418 is a hydration mismatch - server-rendered HTML doesn't match client-side rendering.

Root Cause: The useLocalStorage hook accesses window.localStorage during initial render, which:

  1. Returns different values on server (no localStorage) vs client
  2. Causes hydration mismatch
  3. Results in error #418

Impact:

  • Console errors on every page load
  • Potential rendering issues
  • Breaks React's hydration process

Pages Affected:

  • Text to Image (uses useLocalStorage for form data)
  • Image to Image (uses useLocalStorage for form data)
  • Upscaler (uses useLocalStorage for form data)

Fix Needed: Add proper SSR handling with useEffect to ensure localStorage is only accessed on client-side after hydration.

React hydration error occurs on page load: ``` Uncaught Error: Minified React error #418 ``` **Error Details:** React error #418 is a hydration mismatch - server-rendered HTML doesn't match client-side rendering. **Root Cause:** The `useLocalStorage` hook accesses `window.localStorage` during initial render, which: 1. Returns different values on server (no localStorage) vs client 2. Causes hydration mismatch 3. Results in error #418 **Impact:** - Console errors on every page load - Potential rendering issues - Breaks React's hydration process **Pages Affected:** - Text to Image (uses useLocalStorage for form data) - Image to Image (uses useLocalStorage for form data) - Upscaler (uses useLocalStorage for form data) **Fix Needed:** Add proper SSR handling with `useEffect` to ensure localStorage is only accessed on client-side after hydration.
Szontágh Ferenc відкоментовано 3 місяців тому
Власник

Fixed in commit 614f2b0

Root Cause Analysis: The useLocalStorage hook was accessing window.localStorage during the initial render phase (inside the useState initializer). This caused a React hydration mismatch because:

  1. Server-side: Renders with initialValue (no localStorage available)
  2. Client-side: Hydrates and immediately reads from localStorage (different value)
  3. React: Detects the mismatch and throws error #418

The Problem Code:

const [storedValue, setStoredValue] = useState<T>(() => {
  if (typeof window === 'undefined') {
    return initialValue;
  }
  const item = window.localStorage.getItem(key);
  return item ? JSON.parse(item) : initialValue; // Different on client!
});

Even with the typeof window check, this still caused hydration issues in Next.js.

The Solution: Implemented the standard SSR-safe localStorage pattern:

// Always start with initialValue (same on server and client)
const [storedValue, setStoredValue] = useState<T>(initialValue);

// Load from localStorage AFTER hydration (client-side only)
useEffect(() => {
  try {
    const item = window.localStorage.getItem(key);
    if (item) {
      setStoredValue(JSON.parse(item));
    }
  } catch (error) {
    console.warn(`Error loading localStorage key "${key}":`, error);
  }
}, [key]);

Why This Works:

  1. Both server and client render with initialValue initially
  2. After hydration completes, useEffect runs (client-side only)
  3. localStorage value is loaded and state updates
  4. No hydration mismatch, no errors

Changes:

  • Modified webui/lib/hooks.ts
  • Changed from useState initializer to useEffect pattern
  • Reduced code complexity by 2 lines

Result: ✅ No more React error #418
✅ Form data persistence still works correctly
✅ Clean console, no warnings
✅ Smooth page loads
✅ Proper SSR support

The fix is now live and affects all pages using form persistence (text2img, img2img, upscaler).

## Fixed in commit 614f2b0 **Root Cause Analysis:** The `useLocalStorage` hook was accessing `window.localStorage` during the initial render phase (inside the `useState` initializer). This caused a React hydration mismatch because: 1. **Server-side:** Renders with `initialValue` (no localStorage available) 2. **Client-side:** Hydrates and immediately reads from localStorage (different value) 3. **React:** Detects the mismatch and throws error #418 **The Problem Code:** ```typescript const [storedValue, setStoredValue] = useState<T>(() => { if (typeof window === 'undefined') { return initialValue; } const item = window.localStorage.getItem(key); return item ? JSON.parse(item) : initialValue; // Different on client! }); ``` Even with the `typeof window` check, this still caused hydration issues in Next.js. **The Solution:** Implemented the standard SSR-safe localStorage pattern: ```typescript // Always start with initialValue (same on server and client) const [storedValue, setStoredValue] = useState<T>(initialValue); // Load from localStorage AFTER hydration (client-side only) useEffect(() => { try { const item = window.localStorage.getItem(key); if (item) { setStoredValue(JSON.parse(item)); } } catch (error) { console.warn(`Error loading localStorage key "${key}":`, error); } }, [key]); ``` **Why This Works:** 1. Both server and client render with `initialValue` initially 2. After hydration completes, `useEffect` runs (client-side only) 3. localStorage value is loaded and state updates 4. No hydration mismatch, no errors **Changes:** - Modified `webui/lib/hooks.ts` - Changed from `useState` initializer to `useEffect` pattern - Reduced code complexity by 2 lines **Result:** ✅ No more React error #418 ✅ Form data persistence still works correctly ✅ Clean console, no warnings ✅ Smooth page loads ✅ Proper SSR support The fix is now live and affects all pages using form persistence (text2img, img2img, upscaler).
Підпишіться щоб приєднатися до обговорення.
Без Мітки
bug
ui
Етап відсутній
Немає відповідального
1 учасників
Завантажується...
Скасувати
Зберегти
Тут ще немає жодного вмісту.