Renderizar listas largas en React puede volverse pesado si no controlas qué se calcula y cuándo. Con useMemo, React.memo, Suspense y TanStack Query puedes paginar cursos de forma fluida, mostrando solo los elementos necesarios por página y evitando renders innecesarios. Esta guía te muestra cómo armar ese flujo paso a paso, ideal si trabajas con dashboards, catálogos o cualquier UI con datos paginados.
Cómo calcular los cursos visibles por página con useMemo
La idea central es sencilla: en lugar de renderizar el array completo, calculas en memoria solo el rango que corresponde a la página actual. Y aquí entra memoization, una técnica que guarda el resultado de un cálculo y lo reutiliza hasta que cambien sus dependencias [01:00].
Declaras una variable currentCourses envuelta en useMemo. Dentro pasas una función que retorna courses.slice(indexOfFirstCourse, indexOfLastCourse). Ese slice es un método nativo de arrays que recorta el listado entre dos índices, justo lo que necesitas para una paginación.
¿Qué hace useMemo en React? Memoriza el resultado de una función y solo lo recalcula cuando cambia alguna de sus dependencias. Evita trabajo repetido en cada render.
Las dependencias del hook son tres: el array courses, la currentPage y la cantidad de cursos por página. Cuando cualquiera cambia, React recalcula el slice; si no, reutiliza el valor anterior.
Cómo defino los índices de inicio y fin
Necesitas dos variables para que slice sepa de dónde a dónde cortar:
indexOfFirstCourse: se calcula como currentPage * coursesPerPage.
indexOfLastCourse: parte del primer índice y suma los cursos por página.
- Caso borde: si
courses viene vacío o indefinido, retornas un array vacío para evitar errores en el render.
Un detalle que aparece al hacer debugging con console.log es fácil confundir el orden de los índices. Si ves que el primer índice sale como 2 y el segundo como 0, revisa los nombres: lo más probable es que hayas intercambiado first y last en el slice [05:30].
Cómo conecto TanStack Query como proveedor global
Para que la app pueda leer los datos que vienen de tu API, envuelves la aplicación en un QueryClientProvider. Este provider expone el cliente de queries a todo el árbol de componentes.
En tu main, importas QueryClientProvider y QueryClient desde @tanstack/react-query. Luego creas la instancia: const queryClient = new QueryClient() y la pasas como prop al provider con client={queryClient}.
jsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
Con eso, cualquier componente hijo puede consumir queries sin configurar nada extra.
Cómo manejo la carga con Suspense y React.memo
Dentro del provider envuelves el componente de lista en <Suspense>, importado desde react. Suspense maneja el estado de carga mientras los datos llegan, y le pasas un fallback que se muestra entre tanto.
jsx
<Suspense fallback={<div>Loading courses</div>}>
<CourseList />
</Suspense>
El fallback puede ser un div simple con un texto como “Loading courses”, un spinner o cualquier componente de placeholder. Lo importante es que el usuario vea algo mientras la data carga.
¿Para qué sirve React.memo? Es una función de orden superior que evita que un componente se vuelva a renderizar si sus props no cambiaron. Útil para listas y elementos que reciben los mismos datos varias veces.
Para que el componente de lista no se redibuje innecesariamente, lo envuelves con React.memo. La sintaxis es directa: export default React.memo(CourseList). Recuerda importar React from 'react' si aún no lo tienes en el archivo.
Qué técnicas de React están trabajando juntas aquí
El resultado es una paginación que se siente instantánea porque varias optimizaciones se complementan:
- useMemo para calcular solo el slice necesario por página.
- React.memo para evitar renders del componente cuando las props no cambian.
- Suspense para mostrar un fallback mientras los datos cargan.
- TanStack Query para gestionar el fetch, caché y estados de la API.
- Code splitting y useTransition para mantener la UI responsiva.
Un detalle final de UI: agregar un <h1> con un título como “Learning courses” y ajustar los estilos en index.css ayuda a que la sección se sienta terminada [08:30]. La paginación queda funcional, los botones cambian de página y los cursos se renderizan sin saltos visibles.
¿Has probado combinar useMemo con TanStack Query en tus proyectos? Cuéntame en los comentarios qué patrón de paginación usas y qué resultados te ha dado.