Construir un sistema de paginación eficiente en React requiere algo más que dividir datos en páginas. En esta práctica se combinan useMemo, TanStack Query y React.memo para renderizar únicamente los cursos necesarios por página, evitando renders innecesarios y garantizando una experiencia fluida.
¿Cómo funciona useMemo para paginar cursos?
El concepto central es memoization [0:12]: una técnica que permite calcular un valor solo cuando sus dependencias cambian, en lugar de recalcularlo en cada render. Para aplicarlo se crea una variable llamada currentCourses utilizando el hook useMemo.
Dentro de useMemo se define una función que recibe el array completo de cursos y devuelve únicamente los que corresponden a la página actual. La clave está en el método de arrays slice [1:17], que recibe dos índices: el del primer curso y el del último curso que se deben mostrar.
javascript
const currentCourses = useMemo(() => {
if (!courses) return [];
return courses.slice(indexOfFirstCourse, indexOfLastCourse);
}, [courses, currentPage, coursesPerPage]);
- Si no hay cursos disponibles, se retorna un array vacío para evitar errores.
- Las dependencias del hook son
courses, currentPage y coursesPerPage [2:05].
- Cuando cualquiera de estas dependencias cambia,
useMemo vuelve a ejecutar el cálculo.
¿Cómo se calculan los índices de paginación?
Para determinar qué porción del array mostrar se necesitan dos variables [2:24]:
indexOfLastCourse: se obtiene multiplicando currentPage por coursesPerPage.
indexOfFirstCourse: se obtiene restando coursesPerPage al índice del último curso.
javascript
const indexOfLastCourse = currentPage * coursesPerPage;
const indexOfFirstCourse = indexOfLastCourse - coursesPerPage;
Un detalle importante que surgió durante el debugging [5:24]: si se confunde el orden de estos índices, el primer valor será mayor que el segundo y slice devolverá un array vacío. Verificar con console.log los valores de ambos índices permitió detectar y corregir el error rápidamente.
¿Por qué envolver la app con QueryClientProvider?
Para que los datos de la API lleguen correctamente al componente, la aplicación debe estar envuelta en un QueryClientProvider [3:08] de TanStack Query. Este proveedor necesita una instancia de QueryClient.
javascript
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
- QueryClient es la instancia que gestiona el caché y las peticiones.
- QueryClientProvider la inyecta en todo el árbol de componentes.
¿Qué papel juegan Suspense y React.memo?
Dentro del proveedor se utiliza Suspense [3:53] de React para manejar el estado de carga del componente. Mientras los datos no estén disponibles, se muestra un fallback con el mensaje "Loading courses".
jsx
<Suspense fallback={<div>Loading courses</div>}>
<CourseList />
</Suspense>
Además, el componente de lista se envuelve con React.memo [4:28], una función de orden superior que evita que el componente se vuelva a renderizar si sus props no han cambiado. Esto complementa a useMemo: mientras uno memoriza el cálculo de datos, el otro memoriza el renderizado del componente.
¿Qué técnicas de rendimiento se combinan en esta aplicación?
El resultado final es un paginado funcional que integra varias estrategias de optimización [6:37]:
- useMemo para calcular los cursos visibles solo cuando es necesario.
- TanStack Query para gestionar el fetching y caché de datos.
- Suspense para mostrar estados de carga sin lógica condicional manual.
- React.memo para prevenir renders innecesarios del componente.
- Code splitting y useTransition para mantener la interfaz fluida durante las transiciones de página.
El proceso de debugging con console.log también demostró lo importante que es verificar los valores intermedios cuando el resultado no es el esperado. Un simple intercambio de variables fue suficiente para que la paginación funcionara correctamente.
¿Has implementado paginación en tus proyectos con alguna de estas técnicas? Comparte tu experiencia o dudas en los comentarios.