Este blog va a cargar rápido

Código
Por: Mateo Lewinzon / Publicado el 8 mar. 2023
- visitas6 min de lectura

Los problemas con la recuperación de datos tradicional en React

Cuando se trata de construir aplicaciones web con React, hay un problema común al que se enfrentan muchos desarrolladores: la recuperación de datos. En una aplicación React típica, cuando un usuario entra en una página, el navegador primero carga un archivo HTML vacío. Luego, se ejecuta el código JavaScript que recupera los datos del servidor y finalmente, los datos se representan en la pantalla. Este enfoque tradicional tiene algunos problemas.

Contenido vacío mientras se buscan los datos

En primer lugar, este proceso puede llevar algún tiempo y el usuario puede ver una página en blanco o un spinner de carga durante este proceso, lo que puede ser molesto.

Este problema puede ser muy pronunciado al tratar con la búsqueda de datos complejos, como la recuperación de datos de múltiples APIs o bases de datos. En estos casos, el tiempo requerido para cargar la página puede ser demasiado largo. Aunque esto se puede mitigar utilizando elementos de UI como los spinners de carga, conduce a una mala experiencia de usuario.

Imaginate una página de artículo de blog como esta, utilizando el enfoque tradicional de hacer fetch al contenido dentro de useEffect.

import React, { useState, useEffect } from 'react';

function Article() {
  const [article, setArticle] = useState(null);

  useEffect(() => {
    async function fetchData() {
      const response = await fetch('https://api.example.com/articles/1');
      const data = await response.json();
      setArticle(response.data);
    }
    fetchData();
  }, []);

  if (!article) {
    return <div>Loading...</div>;
  }

  return (
    <div>
      <h1>{article.title}</h1>
      <p>{article.content}</p>
    </div>
  );
}

export default Article;

Una vez que se sirve el HTML inicial, el sitio web está vacío hasta que termine de obtener el artículo. Incluso si son solo un par de milisegundos, el contenido aparecerá de repente en la pantalla. Hay una mejor manera, créanme.

Mal SEO

Este enfoque también afecta la optimización para motores de búsqueda. Si el HTML que se sirve primero al cliente está vacío, los motores de búsqueda tendrán dificultades para rastrear su sitio web. Quizás esto no sea relevante para su aplicación, por ejemplo, si estás construyendo una aplicación de back office para uso interno. Pero para la mayoría de los casos, la optimización de SEO es importante y no se proporciona automáticamente en React.

Server rendering: La forma moderna de obtener datos

Los problemas anteriores se pueden solucionar mediante la implementación de métodos de renderizado en el servidor. Con estos métodos, a diferencia del renderizado en el lado del cliente (como se muestra arriba), el HTML servido ya estará poblado con contenido cuando llegue al cliente.

Todo el proceso de renderizado ocurre en el servidor, por lo que los datos se obtendrán y el contenido estará listo al momento en que cargue la página. No más spinners ni contenido que relampaguee. Además, en cuanto al SEO, los motores de búsqueda podrán rastrear los sitios web con facilidad, ya que encontrarán HTML ya poblado.

Next.js es un framework popular que, entre otras cosas, tiene soporte incorporado para los métodos de renderizado en el servidor.

Así funciona cada uno de los métodos:

Server Side Rendering (SSR)

El servidor renderiza la página y envía un archivo HTML completamente formado al cliente cada vez que se solicita. Esto se conoce comúnmente como "renderizado en el servidor bajo demanda". SSR es genial, pero puede ser lento y consumir muchos recursos, especialmente para aplicaciones a gran escala.

Si el contenido se actualiza constantemente (por ejemplo, un feed de redes sociales) o si requiere o depende de la autenticación (por ejemplo, la página "Mi usuario"), SSR es la mejor opción. Cuando se requiere que se ejecute código en el lado del servidor EN CADA solicitud de página, esta será siempre la mejor solución.

Sin embargo, como verás, el SSR no es necesario para el contenido que solo consume datos estáticos o para las páginas que no cambian con frecuencia. Toma esta página de artículo de blog como ejemplo. No tendría sentido renderizar el artículo en el servidor en cada solicitud. Si no cambia, ¿por qué no renderizarlo solo una vez?

Static Site Generation (SSG)

Una mejor solución es utilizar la Generación de sitios estáticos (SSG), que genera los archivos HTML de antemano durante el proceso de compilación. Esto significa que cuando un usuario solicita una página, el archivo HTML ya está pre-renderizado y se puede servir de inmediato, sin necesidad de obtener o procesar el renderizado en el servidor. Esto resulta en una experiencia de usuario mucho más rápida, ya que la página aparece al instante, sin retraso o spinner de carga.

Los archivos HTML de este sitio web (incluidos cada artículo del blog) se generan en el servidor cuando se construye la aplicación para que estén listos en el momento en que se soliciten.

Incremental Static Regeneration (ISR)

Next.js también ofrece soporte para la Regeneración Estática Incremental (ISR), que, además de SSG, permite volver a generar las páginas bajo demanda, en función de los cambios de datos. Esto es útil para el contenido estático que aún tiene algunas actualizaciones, como un blog o un sitio de noticias. Con ISR, la página se pre-renderiza inicialmente durante el proceso de construcción, pero luego se actualiza en segundo plano cuando hay nuevos datos disponibles, asegurando que el usuario siempre vea la información más reciente.

Mis página de listado de blogs utiliza ISR. Es re-renderizada cuando es solicitada luego de un mínimo de 24hs de no recibir solicitudes. Es decir, cada día, alguna solicitud a la página va a "revalidar" los datos haciendo una renderización on-demand, y guardando el nuevo HTML actualizado.

Como estoy constantemente actualizando mi página personal (por ende re-renderizando todo en las builds) me basta con esta solución simple, pero se podría hacer algo más sofisticado configurando un endpoint para regenerar cuando uno quiera. Por ejemplo:

GET /api/posts/regenerate?secretAdminPassword=123

Cuando publicamos un artículo nuevo, enviamos esta request. El servidor recibe esta señal y renderiza nuevamente nuestra página, manteniendo el HTML actualizado todo el tiempo y así evitando que nuestros usuarios carguen un server render.

Pre-fetching

Además de los métodos de renderizado en el servidor, Next.js nos permite hacer pre-fetch fácilmente en los enlaces internos visibles en nuestra página. Cuando esto sucede para SSG, Next.js buscará toda la página de antemano, por lo que cuando se hace clic en el enlace, es prácticamente una transición instantánea.

Conclusión

En resumen, el renderizado en el servidor es una herramienta poderosa que puede mejorar considerablemente el rendimiento y la experiencia del usuario de sus aplicaciones web basadas en React. Al usar SSG, se puede pre-renderizar páginas durante el proceso de build, eliminando la necesidad de buscar datos en el lado del servidor y reduciendo significativamente el tiempo de carga. Y con el soporte para ISR, se puede mantener sus páginas actualizadas con los datos más recientes, sin sacrificar el rendimiento o la experiencia del usuario.