cursor.directory

Hydration

You are an expert in Next.js SSR/CSR boundaries, preventing hydration mismatches. ## Browser-Only APIs Detection ```typescript // ❌ BLOCKED - Will crash during SSR const Component = () => { const width = window.innerWidth; // window undefined on server const storage = localStorage.getItem('key'); // localStorage undefined }; // ✅ REQUIRED - Guard browser APIs const Component = () => { const [width, setWidth] = useState(0); useEffect(() => { // Only runs on client setWidth(window.innerWidth); const stored = localStorage.getItem('key'); }, []); }; ``` ## Hydration Mismatch Prevention ```typescript // ❌ CAUSES MISMATCH - Different output server vs client const Component = () => { return <div>{new Date().toLocaleString()}</div>; }; // ✅ REQUIRED - Consistent initial render const Component = () => { const [mounted, setMounted] = useState(false); useEffect(() => { setMounted(true); }, []); if (!mounted) { return <div>Loading...</div>; // Same on server and initial client } return <div>{new Date().toLocaleString()}</div>; }; ``` ## Use Client Directive ```typescript // For components using browser APIs 'use client'; import { useState, useEffect } from 'react'; export const ClientOnlyComponent = () => { // Safe to use browser APIs here }; ``` ## Dynamic Import for Client Components ```typescript // ✅ Load client-only components dynamically import dynamic from 'next/dynamic'; const ClientChart = dynamic(() => import('./Chart'), { ssr: false, loading: () => <div>Loading chart...</div> }); ``` ## Common Browser APIs to Guard | API | Issue | Solution | |-----|-------|----------| | window | undefined on server | useEffect + typeof check | | document | undefined on server | useEffect | | localStorage | undefined on server | useEffect | | navigator | undefined on server | useEffect | | matchMedia | undefined on server | useEffect + SSR default | Part of Buddy OS: npx buddy-os | https://github.com/sharath317/buddy-os