Cómo solucionar el error \"Text content does not match server-rendered HTML\" en Next.js App Router
Cómo solucionar el error "Text content does not match server-rendered HTML" en Next.js App Router Este error ocurre cuando el HTML generado en el servidor (SSR/SSG) no coincide con el árbol de React que se construye durante la primera renderización en el navegador (hydration). Es un problema crítico de consistencia de estado que rompe la experiencia de usuario y puede causar comportamientos impredecibles. 🔍 Causa raíz (diagnóstico técnico) En tu caso, el error está relacionado con contenido dinámico que varía entre renderizado del servidor y renderizado del cliente , probablemente causado por: Uso de Date() , Math.random() , localStorage , window , o APIs del navegador directamente en el render . Uso de typeof window !== 'undefined' como condición de renderizado (no es idempotente entre SSR y CSR). Metaetiquetas de detección automática de iOS ( format-detection ) que inyectan nodos <a> en tiempo de ejecución. Extensiones del navegador (especialmente en desarrollo) que modifican el DOM. Librerías CSS-in-JS mal configuradas que inyectan clases o estilos dinámicos en CSR. ⚠️ Nota crítica : Next.js App Router no permite el uso de useEffect para evitar el mismatch en el primer render — el mismatch debe prevenirse , no suprimirse . ✅ Solución definitiva (pasos verificados) Paso 1: Elimina toda lógica no determinista del render NUNCA uses lo siguiente directamente en el cuerpo del componente: // ❌ Evitar const now = new Date (); // ❌ const isClient = typeof window !== ' undefined ' ; // ❌ const randomId = Math . random (); // ❌ const theme = localStorage . getItem ( ' theme ' ); // ❌ ✅ Reemplaza con: // ✅ Usar `useEffect` para *actualizar* el estado, no para *determinar* el render inicial import { useState , useEffect } from ' react ' ; export default function Component () { const [ time , setTime ] = useState < string > ( '' ); // Inicializa con valor seguro (ej. string vacío o placeholder) useEffect (() => { setTime ( new Date (). toISOString ()); }, []); return < time d