Todos hemos padecido la frustración de esperar ante pantallas de carga largas, solo para encontrarnos atascados con páginas inresponsivas. Vemos spinner de carga por todas partes, pero nada parece avanzar. Permítanme pintarles una imagen más clara:
Esto suele ocurrir porque el sitio web está tratando de obtener toda la información necesaria inmediatamente después de que se haya abierto la página. Puede ser que se esté procesando una solicitud a una API o que varias API estén obteniendo datos secuencialmente, causando demoras en la carga de la página.
El resultado? Una mala experiencia del usuario. Pueden pensar, “¿Cómo puede una gran empresa no priorizar la experiencia del usuario? Esto es decepcionante.” En consecuencia, los usuarios a menudo salen del sitio, afectando las métricas clave y potencialmente impactando los ingresos.
Pero ¿y si pudieran obtener los datos para estas páginas pesadas antes de tiempo, de modo que cuando un usuario llegue a la página, pueda interactuar con ella inmediatamente?
Este es el concepto de prefetching, y es exactamente lo que abordaremos en este artículo de blog. Así que sin más demora, vamos a empezar!
Tabla de contenidos
Prefetching como solución
Aquí está la versión revisada con sólo las correcciones de gramática y ortografía:
Para el problema anterior, lo que queremos es cargar los datos de una página determinada antes de que se haya cargado el sitio web, de modo que el usuario no tenga que cargar los datos al cargar la página. Esto se conoce como prefetching. Desde una perspectiva técnica, su definición es la siguiente:
Se trata de una manera de cargar los datos necesarios previamente para que el componente principal no tenga que esperar los datos, mejorando así la experiencia.
Esto puede mejorar la experiencia del usuario, aumentando la confianza del cliente en su sitio web.
El prefetching es una solución simple y elegante que prioriza al usuario más que un proceso estándar. Para implementar el prefetching, necesitamos entender el comportamiento del usuario en el sitio web. Es decir, las páginas más visitadas o los componentes que carguen datos en pequeñas interacciones (como el mouseover).
Después de analizar tales escenarios, resulta lógico aplicar el prefetching a ellos. Sin embargo, como desarrolladores, deberíamos tener cuidado con el uso de este concepto. Demasiado prefetching también puede ralentizar tu sitio web, ya que estás intentando cargar mucha información para escenarios futuros, lo que puede bloquear la carga de información para la página principal.
Cómo el Prefetching Mejora la Experiencia del Usuario
Veamos algunos escenarios en los que el prefetching es beneficioso:
-
Cargar datos/página más temprano para el enlace más visitado desde tu página de llegada. Por ejemplo, considere que tienes un enlace a “contactanos”. Supongamos que este es el enlace que los usuarios más verifican y contiene mucha información al cargar. En lugar de cargar los datos cuando la página de Contactanos carga, simplemente puedes buscar los datos en la página de inicio de modo que no tengas que esperar en la página de Contactanos para la información. Puedes leer más sobre la carga previa de páginas aquí.
-
Prefetching de datos de tabla para páginas posteriores.
-
Obteniendo datos de un componente padre y cargándolos en el componente hijo.
-
Preparando datos que deben mostrarse en un tooltip.
Estas son algunas de las maneras de lograr la pre-carga en tu aplicación y cómo ayuda a mejorar la experiencia del usuario.
En este artículo de blog, vamos a discutir sobre el último escenario: “preparar datos que deben mostrarse en el tooltip”. Este es un ejemplo clásico en el que la pre-carga puede ser beneficiosa y proporciona una experiencia más suave al usuario.
Comprensión del Problema
Permítanme definir el problema aquí. Imagina el siguiente escenario:
-
Tienes un componente que muestra información específica.
-
Hay un elemento dentro de este componente que muestra otro tooltip cuando se pasa el cursor sobre él.
-
El tooltip carga datos cuando se inicia.
Ahora imagina que el usuario pasa el cursor sobre el elemento y tiene que esperar que los datos se carguen y muestren en el tooltip. Durante esta espera, ve la animación de carga.
El escenario se verá así:
Es frustrante ver cómo el usuario tiene que esperar mucho tiempo cada vez que pasa el cursor sobre la imagen:
Para resolver este problema, hay dos soluciones que pueden ayudarle a empezar y optimizar la solución según sus necesidades.
Solución #1: Precarga de Datos en el Componente Padre
Esta solución se inspiró en el blog de Martin Fowler. Permite recuperar los datos antes de que aparezca el cuadro de dialogo, en lugar de recuperarlos cuando se carga el componente.
El cuadro de dialogo aparece cuando se pasa el cursor sobre él. Podemos recuperar los datos cuando el ratón entra en el componente padre. Antes de que el componente real, la imagen, se pase con el cursor, tendremos los datos para el cuadro emergente y los pasaremos al componente de cuadro emergente.
Esta solución no elimina por completo el estado de carga, pero ayuda a reducir significativamente las posibilidades de ver el estado de carga.
Solución #2: Precarga de Datos en la Carga de Página
Esta solución se inspiró en x.com donde, para el componente de cuadro emergente, recuperan los datos parcialmente en la carga de la página principal y recuperan el resto de los datos cuando el componente se monta.
Como puede ver en el video de arriba, los detalles del perfil del usuario se ven en el cuadro emergente. Si mira de cerca, los detalles relacionados con los seguidores se recuperan más tarde.
Esta técnica es altamente eficiente cuando tienes muchos datos que mostrar en el popover, pero recuperarlos puede ser costoso en el momento del montaje del popover o en el carga de la página principal.
Una mejor solución sería cargar parcialmente los datos requeridos en la página principal y cargar el resto de los datos cuando el componente se monta.
En nuestro ejemplo, recuperamos los datos para el popover cuando el cursor entra en el elemento padre de la imagen. Ahora imagina que necesitas recuperar detalles adicionales una vez que se haya cargado los datos del popover. Así que basándonos en el método de x.com, podemos recuperar datos adicionales al cargar el popover. Aquí es el resultado de eso:
En este caso, hacemos lo siguiente:
-
Recuperamos los datos principales que son solo necesarios para renderizar el popover cuando el ratón entra en el componente padre de la imagen.
-
Esto nos da suficiente tiempo para recuperar los datos principales.
-
Al cargar el popover, recuperamos otro dato, que es el conteo de álbumes. Mientras el usuario lee datos como el nombre y el correo electrónico, tendremos los siguientes datos listos para verse.
De esta forma, podemos hacer pequeñas y inteligentes modificaciones para minimizar la mirada vacía de los cargadores en la pantalla 😊.
Cómo implementar la pre-carga con React.
En esta sección brevemente recorremos cómo implementar la aplicación de pre-carga de arriba.
Configuración del proyecto
Para empezar a crear la aplicación de pre-carga, siga con el proceso descrito a continuación:
Puede utilizar vitejs (esto es lo que use yo) o create-react-app para crear su aplicación. Copie el comando de abajo en su terminal:
yarn create vite prefetch-example --template react-ts
Una vez que se haya creado la aplicación, debería tener la siguiente estructura de carpetas al abrir la carpeta prefetch-example con VS Code.
Ahora vamos a adentrarnos en los componentes que vamos a construir para esta aplicación.
Componentes
En este ejemplo vamos a utilizar 3 componentes:
-
PopoverExample
-
UserProfile
-
UserProfileWithFetching
PopoverExample
Componente
Comencemos con el primer componente, que es el PopoverExample
. Este componente muestra una imagen de avatar y algo de texto a la derecha de él. Debería verse así:
El propósito de este componente es servir como un ejemplo similar a los escenarios reales de la vida. La imagen en este componente carga un componente de popover cuando se pasa el cursor sobre él.
Aquí está el código para el componente:
import { useState } from "react";
import { useFloating, useHover, useInteractions } from "@floating-ui/react";
import ContentLoader from "react-content-loader";
import UserProfile from "./UserProfile";
import UserProfileWithFetching from "./UserProfileWithFetching";
export const MyLoader = () => (
<ContentLoader
speed={2}
width={340}
height={84}
viewBox="0 0 340 84"
backgroundColor="#d1d1d1"
foregroundColor="#fafafa"
>
<rect x="0" y="0" rx="3" ry="3" width="67" height="11" />
<rect x="76" y="0" rx="3" ry="3" width="140" height="11" />
<rect x="127" y="48" rx="3" ry="3" width="53" height="11" />
<rect x="187" y="48" rx="3" ry="3" width="72" height="11" />
<rect x="18" y="48" rx="3" ry="3" width="100" height="11" />
<rect x="0" y="71" rx="3" ry="3" width="37" height="11" />
<rect x="18" y="23" rx="3" ry="3" width="140" height="11" />
<rect x="166" y="23" rx="3" ry="3" width="173" height="11" />
</ContentLoader>
);
export default function PopoverExample() {
const [isOpen, setIsOpen] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [data, setData] = useState({});
const { refs, floatingStyles, context } = useFloating({
open: isOpen,
onOpenChange: setIsOpen,
placement: "top",
});
const hover = useHover(context);
const { getReferenceProps, getFloatingProps } = useInteractions([hover]);
const handleMouseEnter = () => {
if (Object.keys(data).length === 0) {
setIsLoading(true);
fetch("https://jsonplaceholder.typicode.com/users/1")
.then((resp) => resp.json())
.then((data) => {
setData(data);
setIsLoading(false);
});
}
};
return (
<div
id="hover-example"
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
textAlign: "left",
}}
onMouseEnter={handleMouseEnter}
>
<span
style={{
padding: "1rem",
}}
>
<img
ref={refs.setReference}
{...getReferenceProps()}
style={{
borderRadius: "50%",
}}
src="https://cdn.jsdelivr.net/gh/alohe/avatars/png/vibrent_5.png"
/>
</span>
<p>
Lorem Ipsum is simply dummy text of the printing and typesetting
industry. Lorem Ipsum has been the industry's standard dummy text ever
since the 1500s, when an unknown printer took a galley of type and
scrambled it to make a type specimen book. It has survived not only five
centuries, but also the leap into electronic typesetting, remaining
essentially unchanged. It was popularised in the 1960s with the release
of Letraset sheets containing Lorem Ipsum passages, and more recently
with desktop publishing software like Aldus PageMaker including versions
of Lorem Ipsum.
</p>
{isOpen && (
<div
className="floating"
ref={refs.setFloating}
style={{
...floatingStyles,
backgroundColor: "white",
color: "black",
padding: "1rem",
fontSize: "1rem",
}}
{...getFloatingProps()}
>
{isLoading ? (
<MyLoader />
) : (
<UserProfile hasAdditionalDetails {...data} />
)}
{/* <UserProfileWithFetching /> */}
</div>
)}
</div>
);
}
Hay varias cosas sucediendo aquí, permítanme explicarlas paso a paso:
-
Tenemos un
div
padre llamadohover-example
que contiene una imagen y algún texto. -
A continuación, renderizamos condicionalmente un
div
con el nombre de clasefloating
. Este es el componente de ventana emergente real que se abre al pasar el cursor sobre la imagen.- Hemos utilizado la
biblioteca
y su ejemplo básico de hover para lograr el efecto de hover para la ventana emergente.
- Hemos utilizado la
-
Adentro de la ventana emergente cargamos condicionalmente el
UserProfile
y el cargador de esqueleto. Este cargador aparece cuando estamos obteniendo los datos del perfil del usuario. Más sobre esto más tarde. -
Hicimos uso de la biblioteca react-content-loader en el componente
MyLoader
. Esta biblioteca también tiene un sitio web que le ayuda a crear cargadores, puede revisarlo aquí.
Componente UserProfile
Ahora que hemos definido nuestro ejemplo de Popover
, es el momento de entrar en los detalles del componente UserProfile
.
Este componente aparece dentro del componente popover. El propósito de este componente es cargar los detalles name
email
phone
website
que se recuperan de API de placeholder de JSON.
Para demostrar el ejemplo de pre-carga, debemos asegurarnos de que el componente UserProfile
solo actúe como un componente presentacional; es decir, no hay lógica de carga explícita dentro de él.
Lo importante que se debe notar sobre este componente es que la carga de datos ocurre desde el componente padre, que es el componente PopoverExample
. En este componente, comenzamos a cargar los datos cuando el ratón entra en este componente (el evento mouseenter
). Esta es la solución #1 que discutimos anteriormente.
Esto nos da suficiente tiempo para cargar los datos hasta que el usuario pasa el cursor sobre la imagen. Aquí está el código:
import { useEffect, useState } from "react";
import ContentLoader from "react-content-loader";
const MyLoader = () => (
<ContentLoader
speed={2}
viewBox="0 0 476 124"
backgroundColor="#d1d1d1"
foregroundColor="#fafafa"
>
<rect x="4" y="43" rx="0" ry="0" width="98" height="30" />
</ContentLoader>
);
export default function UserProfile(props: Record<string, string | boolean>) {
const { name, email, phone, website, hasAdditionalDetails } = props;
const [isLoading, setIsLoading] = useState(false);
const [additionalData, setAdditionalData] = useState(0);
useEffect(() => {
if (hasAdditionalDetails) {
setIsLoading(true);
fetch("https://jsonplaceholder.typicode.com/albums")
.then((resp) => resp.json())
.then((data: Array<unknown>) => {
const albumCount = data.reduce((acc, curr) => {
if (curr.userId === 1) acc += 1;
return acc;
}, 0);
setAdditionalData(albumCount);
})
.finally(() => {
setIsLoading(false);
});
}
}, [hasAdditionalDetails]);
return (
<div id="user-profile">
<div id="user-name">name: {name}</div>
<div id="user-email">email: {email}</div>
<div id="user-phone">phone: {phone}</div>
<div id="user-website">website: {website}</div>
{hasAdditionalDetails && (
<>
{isLoading ? (
<MyLoader />
) : (
<div id="user-albums">Album Count: {additionalData}</div>
)}
</>
)}
</div>
);
}
Este componente utiliza la propiedad hasAdditionalDetails
. El propósito de esta propiedad es cargar datos adicionales cuando el componente se monta. Ilustra la solución #2 mencionada arriba.
Componente UserProfileWithFetching
Este componente es muy similar al componente UserProfile
. Solo contiene la lógica para cargar datos cuando el componente se carga. El propósito de este componente es mostrar cómo se vería la solución general sin la técnica de pre-carga.
Así que este componente siempre cargará los datos cuando el componente se monta, lo que muestra el cargador de esqueleto.
Aquí está el código:
import { useEffect, useState } from "react";
import { MyLoader } from "./PopoverExample";
export default function UserProfileWithFetching() {
const [isLoading, setIsLoading] = useState(false);
const [data, setData] = useState<Record<string, string>>({});
useEffect(() => {
setIsLoading(true);
fetch("https://jsonplaceholder.typicode.com/users/1")
.then((resp) => resp.json())
.then((data) => {
setData(data);
setIsLoading(false);
});
}, []);
if (isLoading) return <MyLoader />;
return (
<div id="user-profile">
<div id="user-name">name: {data.name}</div>
<div id="user-email">email: {data.email}</div>
<div id="user-phone">phone: {data.phone}</div>
<div id="user-website">website: {data.website}</div>
</div>
);
}
El código completo de esta aplicación se puede encontrar aquí.
También puede causar lentitud demasiada pre-carga
Un consejo, demasiada pre-carga no es buena porque:
-
Puede retardar tu aplicación.
-
Puede empeorar la experiencia del usuario si no se aplica la pre-carga de manera estratégica.
La pre-carga debe aplicarse cuando se conoce el comportamiento del usuario. Es decir, se puede predecir el movimiento del usuario por medidas y saber si visita una página con frecuencia. En ese caso, la pre-carga es una buena idea.
Así que recuerda aplicar siempre la pre-carga de manera estratégica.
Resumen
¡Eso es todo, amigos! Espero que les guste mi entrada de blog. En este artículo de blog, has aprendido que la implementación de la pre-carga puede mejorar significativamente la velocidad y la respuesta de tu aplicación web, mejorando la satisfacción del usuario.
Para leer más, consulta los siguientes artículos:
Para más contenido, puedes seguir conmigo en Twitter, GitHub, y LinkedIn.
Source:
https://www.freecodecamp.org/news/boost-web-performance-with-prefetching/