Contenido del curso
Crea tu primer app con SSR
- 6

Proyecto Helix Eye: de CSR a SSR
14:50 min - 7

Webpack para servidor Node con TypeScript
16:19 min - 8

Servidor Express con TypeScript desde cero
08:48 min - 9

Función template HTML dinámica en TypeScript
06:52 min - 10

renderToString y StaticRouter en el servidor
10:35 min - 11

Hidratación de React con hydrateRoot en SSR
Viendo ahora - 12

Prefetching de API en el servidor con Axios
13:00 min - 13

Inyectando initialProps del servidor a React
09:19 min - 14

Cómo inyectar estilos de SSR sin flickering
09:56 min
Bonus
Hidratación de React con hydrateRoot en SSR
Resumen
El proceso de hidratación en server-side rendering con React es el paso final para que tu aplicación pase de ser HTML estático enviado desde el servidor a una aplicación interactiva en el navegador. Si estás trabajando con SSR y necesitas activar el JavaScript del cliente sobre el árbol de elementos ya renderizado, aquí tienes el flujo completo.
La idea base es sencilla: el servidor envía una instantánea del DOM como texto plano y, una vez que el navegador la recibe, React toma ese árbol existente y lo hidrata con los event handlers y la lógica de JavaScript correspondiente.
Cómo configurar el build del cliente con Webpack
Antes de hidratar, necesitas un bundle del cliente que el navegador pueda consumir. Para eso, ajustas la configuración de Webpack y agregas un script en el package.json.
Qué cambios hago en la configuración de Webpack
La configuración del cliente reutiliza la base anterior, con un ajuste clave: eliminar el plugin que generaba el archivo HTML automáticamente. Como el HTML ya se envía desde el servidor, ese plugin sobra [01:00].
En package.json agregas un script build:client con la misma estructura del script de servidor, pero apuntando a la configuración del cliente. Al ejecutar yarn build:client, deberías ver en la carpeta dist el app.js y el favicon.ico listos para servirse [01:50].
¿Por qué quitar el HtmlWebpackPlugin en SSR? Porque el servidor ya genera el HTML inicial con el árbol de React. Si dejas el plugin, terminas con dos HTML compitiendo y el cliente sobreescribe lo que envió el servidor.
Cómo unifico los builds en un solo comando
Para no correr dos comandos por separado, creas un script build que setea NODE_ENV=production y ejecuta primero build:client y luego build:server. Así, al hacer yarn build, se generan ambos bundles dentro de dist [02:30].
Después agregas un script start que corre build y luego node dist/index.js, que es el entry point de tu servidor Express.
Cómo expongo el JavaScript del cliente desde Express
Aunque el servidor ya esté vivo en localhost, el navegador todavía no recibe el app.js. Para servir esos archivos estáticos usas el middleware express.static, que viene incluido en Express.
Apuntas el middleware a la carpeta dist y, en tu template.ts, agregas una etiqueta <script src="app.js" type="text/javascript"></script> justo donde corresponda en el HTML que envías al cliente [04:10]. Recuerda que esa etiqueta no es JSX, así que necesitas la etiqueta de cierre completa.
Con esto, el navegador descarga el bundle y ejecuta React sobre el HTML ya renderizado.
Cómo evitar el doble render al hidratar React
Uno de los errores más comunes en SSR aparece justo aquí: ves la aplicación renderizada dos veces, como si hubiera dos documentos empalmados.
Por qué ocurre el doble render
Cuando el JavaScript se ejecuta, React inserta su árbol de elementos al inicio del HTML, y luego encuentra el div id="app" con el contenido que vino del servidor. El resultado: contenido duplicado.
La solución es asegurarte de que el HTML generado por el servidor se inyecte dentro del div id="app", no fuera de él. Así React reconoce ese contenedor como el punto exacto donde debe hidratar [05:30].
Cuándo uso hydrateRoot en lugar de createRoot
En index.tsx, el cambio crítico es reemplazar createRoot por hydrateRoot. Mientras createRoot crea desde cero el árbol de React, hydrateRoot toma el HTML existente y le agrega la capa interactiva.
tsx import { hydrateRoot } from 'react-dom/client';
hydrateRoot(container, <App />);
No necesitas guardar el resultado en una variable root ni llamar a .render() después, porque hydrateRoot recibe directamente el componente como segundo parámetro [06:20].
¿Qué hace exactamente hydrateRoot? Conecta los event listeners y el estado de React al HTML que ya existe en el DOM, sin volver a renderizarlo. Es la función oficial de React 18 para aplicaciones con SSR.
Cómo verifico que el server-side rendering funciona
La prueba definitiva es desactivar JavaScript en el navegador y recargar la página. Si sigues viendo el contenido renderizado, el servidor está enviando correctamente el HTML inicial.
Luego reactivas JavaScript, recargas y revisas la pestaña Sources de las DevTools: ahí debe aparecer app.js servido desde tu Express [08:10]. Si lo ves, el ciclo completo de SSR está cerrado.
Un detalle fácil de pasar por alto: la variable NODE_ENV=production no solo debe estar al hacer el build, también al levantar el servidor con start. Si la olvidas en el segundo paso, algunas optimizaciones de React no se activan.
Qué viene después de la hidratación: prefetching
Con la hidratación funcionando, ya tienes SSR completo, pero todavía no aprovechas todo el potencial del servidor. En la vista de galaxias, por ejemplo, se renderizan alrededor de 100 elementos cuyos datos siguen pidiéndose desde el cliente con un hook.
El siguiente paso es el prefetching: mover esa petición al lado del servidor, de modo que el HTML llegue al navegador con los datos ya incluidos. Eso reduce el tiempo de carga percibido y mejora el SEO de tu aplicación.
¿Ya implementaste hydrateRoot en algún proyecto propio? Cuéntame en los comentarios qué errores te aparecieron al hacer el cambio desde createRoot.