Como arranxar Minified React error #425 (erro de hidratación)
Resposta rápida
O erro #425 de React —"Text content does not match server-rendered HTML"— é un erro de hidratación: o servidor renderizou un valor e o navegador outro distinto, así que React descarta o HTML do servidor para ese subárbore. O arranxo depende de por que difiren:
- O valor difire de forma lexítima (unha data, unha hora) → engade
suppressHydrationWarning(Arranxo 1). - O valor só existe no navegador (
window,localStorage) → renderízao tras a montaxe (Arranxo 2). - O compoñente enteiro é só-cliente → cárgao con
next/dynamicessr: false(Arranxo 3). - O teu HTML é inválido (un
<div>dentro dun<p>) → corrixe o aniñamento (Arranxo 4).
O erro completo en produción é: Uncaught Error: Minified React error visit https://reactjs.org/docs/error-decoder.html?invariant=425 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
Que significa realmente "Minified React error #425"
Nunha build de produción React envía as mensaxes de erro minificadas para manter o bundle pequeno, así que en vez dunha frase recibes un número e unha ligazón descodificadora (invariant=425). O #425 descodifica a "Text content does not match server-rendered HTML".
Iso só ocorre con renderizado no servidor (Next.js, Remix, renderToString): React renderiza o HTML unha vez no servidor, envíao ao navegador e logo hidrata —reutiliza ese HTML e só engancha os manexadores de eventos, agardando que o primeiro render do cliente produza exactamente a mesma saída—. Cando un anaco de texto sae distinto, a hidratación dese subárbore falla e aparece o #425.
Como a mensaxe está minificada, o paso de depuración máis útil é reproducilo nunha build de desenvolvemento: aí React imprime a mensaxe completa e sinala o elemento exacto, o que converte as conxecturas nun arranxo dunha liña (ver "Como ver o erro real" máis abaixo).
Por que ocorren os erros de hidratación
Todo #425 redúcese a saída do servidor ≠ primeira saída do cliente. Os sospeitosos habituais:
| Causa | Por que difire |
| ----------------------------------------- | -------------------------------------------------------------------- |
| new Date() / toLocaleString | O reloxo/zona do servidor ≠ o reloxo/zona do navegador |
| Math.random(), Date.now(), uuid() | Un valor novo en cada render, servidor e cliente nunca coinciden |
| Formato de número/moeda por locale | O locale do servidor ≠ o do navegador do usuario |
| window, localStorage, navigator | Indefinidos no servidor, presentes no navegador |
| Aniñamento HTML inválido | O navegador "arranxa" o teu HTML, así que o DOM ≠ o que renderizou React |
| Extensións do navegador | Modifican o DOM antes de que React hidrate |

O exemplo de abaixo é o caso clásico: un reloxo en vivo.
O código que provocaba o erro
O servidor renderiza a hora para o seu reloxo e zona horaria; un segundo despois o navegador renderiza a súa —o texto difire e React lanza o #425—.
Arranxo 1 — suppressHydrationWarning para diferenzas de texto lexítimas
Cando a diferenza é real e agardada (un reloxo, un "hai 2 minutos"), dille a React que a acepte nese elemento con suppressHydrationWarning. Só silencia unha diferenza de texto un nivel de profundidade: é un bisturí, non unha manta, así que non o espalles por todas partes.
Arranxo 2 — Renderiza os valores do navegador tras a montaxe
Se o valor sinxelamente non existe no servidor (window, localStorage, matchMedia), renderiza primeiro un marcador estable e substitúeo polo valor real despois de que o compoñente se monte. O servidor e o primeiro render do cliente xa coinciden, e o valor do navegador aparece no seguinte pintado.
Arranxo 3 — Carga os compoñentes só-cliente con next/dynamic
Cando un compoñente enteiro non pode renderizarse nunca no servidor (unha gráfica que le window, un mapa, un editor), sáltate o SSR por completo en vez de protexer cada liña:
Arranxo 4 — Corrixe o aniñamento HTML inválido
Este sorprende porque non hai ningunha data nin valor aleatorio á vista. Se aniñas un elemento de bloque dentro dun <p> (ou un <a> dentro dun <a>, ou un <div> dentro dunha <table> sen <tbody>), o navegador repara o HTML en silencio ao parsealo. React hidrata entón contra un DOM que xa non coincide co que renderizou, e aparece o #425. Non hai atributo que silencie isto: fai que o HTML sexa válido (un <p> só pode conter contido en liña).
Como ver o erro real
Nunca depures o #425 desde o número minificado. Reprodúceo onde React si che fala:
- Next.js: executa
next dev—o desenvolvemento nunca está minificado—. - Build de produción en local:
next build && next start, pero le a mensaxe na consola do navegador, onde React imprime o texto completo e un diff do elemento que non cadra.
React rexistra algo como "Warning: Text content did not match. Server: '14:32' Client: '14:33'", sinalando o nodo exacto. A partir de aí a causa adoita ser obvia.
#418, #422, #423, #425 — a familia de erros de hidratación
Se as túas procuras trouxeron números veciños, son o mesmo problema visto desde ángulos distintos:
| Erro | Significado | | ----- | -------------------------------------------------------- | | #418 | A hidratación fallou porque a UI inicial difería | | #422 | A hidratación rematou pero contiña discrepancias | | #423 | Erro ao hidratar; a árbore caeu a renderizado en cliente | | #425 | O contido de texto non coincide co HTML do servidor |
O arranxo é sempre a mesma disciplina: executa unha build de desenvolvemento, atopa o valor que difire entre servidor e cliente, e reconcíliao cun dos catro arranxos de arriba.
Podes ler máis sobre o atributo na documentación de React.
