hydrateRoot: Server-Rendered HTML

+15 Mana ✨

hydrateRoot lets you display React components inside a browser DOM node whose HTML content was previously generated by react-dom/server.

The Hydration Process

Hydration is the process of attaching React to existing HTML:

  1. Server renders HTML - Users see content immediately
  2. JavaScript loads - React code downloads
  3. Hydration occurs - React attaches event listeners and takes over
tsx
import { hydrateRoot } from 'react-dom/client';
import App from './App';

// The HTML was rendered on the server
const domNode = document.getElementById('root');
const root = hydrateRoot(domNode, <App />);

Key Difference from createRoot

AspectcreateRoothydrateRoot
Starting pointEmpty DOM nodePre-rendered HTML
Initial renderCreates all DOMAttaches to existing DOM
Use caseClient-only appsSSR/SSG apps

Handling Hydration Mismatches

React expects the server HTML to match what it would render. Mismatches cause warnings:

tsx
// Server rendered: <p>Hello, World</p>
// Client renders: <p>Hello, User</p>
// ⚠️ Hydration mismatch!

Suppressing Unavoidable Mismatches

For content that intentionally differs (like timestamps), use suppressHydrationWarning:

tsx
function Timestamp() {
  return (
    <time suppressHydrationWarning>
      {new Date().toLocaleString()}
    </time>
  );
}

Client-Only Content

For content that should only render on the client:

tsx
function ClientOnly({ children }) {
  const [mounted, setMounted] = useState(false);
  
  useEffect(() => {
    setMounted(true);
  }, []);
  
  if (!mounted) return null;
  return children;
}

// Usage
<ClientOnly>
  <BrowserOnlyWidget />
</ClientOnly>

Configuration Options

hydrateRoot accepts the same options as createRoot, plus:

tsx
const root = hydrateRoot(domNode, <App />, {
  onRecoverableError: (error) => {
    // Called when React recovers from hydration mismatches
    console.warn('Hydration mismatch recovered:', error);
  }
});

Updating a Hydrated Root

After hydration, you can update the root like any other:

tsx
const root = hydrateRoot(domNode, <App />);

// Later, update the app
root.render(<App showModal={true} />);
✓ Completed