La paginación puede sentirse lenta si el render es síncrono. Con concurrent mode en React, la interacción al cambiar de página se vuelve asíncrona y fluida. Aquí verás cómo lograrlo con useTransition y Suspense, creando estado local, botones dinámicos y un indicador de loading para una experiencia clara y sin bloqueos.
¿Qué es el concurrent mode y cómo hace fluida la paginación?
El modo concurrente permite que React gestione los renderizados de forma asíncrona. Al pasar de una página a otra, la UI no se congela: muestra un estado pendiente mientras prepara el nuevo contenido. Con useTransition identificas cuándo un cambio de página está “en progreso” y puedes enseñar un mensaje de carga o un loader. Además, se adelanta el uso de Suspense para manejar cargas diferidas.
- Interacción más suave al cambiar de página.
- Render asíncrono con indicador de estado pendiente.
- Preparado para integrar Suspense y lazy loading.
¿Cómo se declara el estado para paginación en React?
Se crea un estado local para la página actual y una constante para la cantidad de cursos por página. Ejemplo del caso explicado: 6 cursos, 3 páginas, 2 cursos por página.
import React, { useState, useTransition } from 'react';
function CoursesView({ courses }) {
const [currentPage, setCurrentPage] = useState(1); // página inicial.
const coursesPerPage = 2; // cantidad por página.
const [isPending, startTransition] = useTransition();
return (
<section>
{/* componente principal en la parte superior */}
<CourseList page={currentPage} perPage={coursesPerPage} />
{/* indicador cuando hay render pendiente */}
{isPending && <p>loading: new page</p>}
{/* botones de paginación irán aquí */}
</section>
);
}
- Estado: currentPage y setCurrentPage con useState.
- Límite por página: coursesPerPage = 2.
- Hook concurrente: [isPending, startTransition] = useTransition().
¿Cómo usar useTransition para indicar cambios de página?
La transición envuelve el cambio de estado. Así, isPending indica si la UI está esperando y muestra un mensaje de loading.
<button
onClick={() => {
startTransition(() => {
setCurrentPage(2); // ejemplo: ir a la página 2.
});
}}
>
2
</button>
- Función clave: startTransition inicia la transición.
- Flag de estado: isPending controla el mensaje de carga.
¿Cómo generar botones de paginación con Array.from?
Los botones se crean con un array dinámico según la división entre el total de cursos y los cursos por página. Se usa el index para numerar y como key.
<div>
{Array.from({ length: (courses.length / coursesPerPage) }, (_, index) => (
<button
key={index}
onClick={() => {
startTransition(() => {
setCurrentPage(index + 1);
});
}}
>
{index + 1}
</button>
))}
</div>
- Cálculo de páginas: total de cursos dividido por coursesPerPage.
- Numeración visible: index + 1 en cada botón.
- Cambio fluido: clic inicia startTransition y actualiza currentPage.
¿Cómo se integran lazy loading y memoización para evitar rerenders?
El siguiente paso es cargar cursos con lazy loading y aplicar memoización para evitar renderizados innecesarios. Así, solo se pintan los elementos cuando hace falta, optimizando el rendimiento y manteniendo la UI estable incluso al navegar entre páginas con useTransition y Suspense.
- lazy loading: carga diferida de componentes o datos.
- Memoización: evita recalcular o renderizar cuando no cambian las dependencias.
- Meta: menos rerenders y experiencia más fluida.
¿Te gustaría ver cómo integrar Suspense, lazy loading y memoización en tu código actual? Cuéntame tu caso y lo ajustamos paso a paso.