Paginación Asíncrona con Concurrent Mode en React

Clase 29 de 31Curso de React Avanzado

Resumen

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.