Paginación: implementación en React, Laravel, JavaScript y Bootstrap

17min

Abordamos de manera práctica el desarrollo de una de las interfaces más utilizadas a la hora de crear sitios web:  la paginación. Explicaremos rápidamente en qué consiste y luego veremos cómo se implementa en diversas tecnologías de desarrollo populares.

Índice

¿Qué es la paginación y por qué es importante?

La paginación es una de las interfaces más comunes a la hora de consumir datos, especialmente cuando la cantidad de ellos es elevada. Consiste en dividir la presentación de un conjunto de resultados amplio en diversas páginas, de modo que sean más fáciles de consumir por los usuarios, a la vez que se evita crear páginas excesivamente largas con datos que puedan recargar las transferencias o el rendimiento del navegador web.

La importancia en el mundo de la web salta a la vista. ¿Podrías imaginar una consulta en Google que arroja millones de resultados sin que éstos se presenten paginados? Obviamente no. Pero tampoco necesitamos irnos a los extremos. Solo con pensar en un comercio electrónico que tenga decenas de productos en una misma categoría, resultaría muy poco práctico que los mostrase todos de una vez. Por tanto, la paginación nos permite no solo mejorar la experiencia de usuario sino también permitir que aumente el rendimiento de las aplicaciones y los sitios web.

Ahora que ya tenemos claro qué es y su importancia, vamos a ver cómo se implementa en distintos tipos de tecnologías de desarrollo.

Implementación de paginación en React

Vamos a comenzar viendo cómo hacer paginación en React, una librería de JavaScript para el desarrollo de interfaces de usuario basadas en componentes. Se trata de una biblioteca que deja bastante libre al desarrollador para implementar las interfaces que necesite, por lo que no existe un solo camino para conseguir paginar los resultados.

De manera general en React (y en JavaScript en general) podemos paginar de dos maneras:

  • Paginación basada en el backend: Es posible que en React estemos usando un backend como servicio web para consultar los datos. Es muy frecuente que este backend nos entregue los datos paginados y en React simplemente tengamos que representar, tal cual, la información que nos llega.
  • Paginar con el propio React: También es posible que el backend nos entregue los datos completos y que nosotros nos encarguemos de paginarlos a la hora de presentarlos al usuario.

En los siguientes puntos vamos a ver cómo se realizaría la paginación en React basada en el segundo supuesto.

Configuración básica de paginación en React

Suponiendo que tengamos un array con resultados en React que deseamos mostrar paginados en una variable «data», el primer paso para implementar la paginación sería crear toda una serie de variables que nos ayuden a definir cómo se debe paginar, como por ejemplo la página actual o los ítem que queremos visualizar por página.

En React basado en Hooks usaríamos un código como este para poder definir los ítems por página y un estado del componente para definir la página que se está visualizando.

const itemsPerPage = 10;
const [currentPage, setCurrentPage] = useState(1);

Luego podríamos calcular los índices del primer y último elemento a mostrar y, por último, acotar el conjunto de ítems actual en función de los datos calculados.

const indexOfLastItem = currentPage * itemsPerPage;
const indexOfFirstItem = indexOfLastItem - itemsPerPage;
const currentItems = data.slice(indexOfFirstItem, indexOfLastItem);

Uso de hooks y estado para manejar la paginación

Los hooks son la manera más habitual de desarrollar componentes basados en funciones. En el caso particular de la paginación se usa especialmente el hook useState, que permite añadir estado a los componentes.

En el código anterior ya hicimos uso de useState. Esta función toma un argumento que es el valor inicial del estado y devuelve un array con dos elementos, que son el propio estado y una función para cambiar el estado. Esto lo hicimos en la línea:

const [currentPage, setCurrentPage] = useState(1);

Por tanto, cuando queramos cambiar la página del componente llamaremos a setCurrentPage. Esto lo podríamos hacer por ejemplo desde un botón o cualquier otro tipo de interfaz:

<button onClick={() => paginate(2)}>Ir a la página 2</button>

La función paginate() es la que llamaría a setCurrentPage para hacer su trabajo.

const paginate = (pageNumber) => setCurrentPage(pageNumber);

Como los ítem del array se calcularon usando el estado currentPage, se actualizarán solo con modificarlo usando setCurrentPage(). Te dejamos un componente de ejemplo usando este código, para que puedas entender el proceso completo de paginación. 

import React, { useState } from 'react';

const PaginatedList = ({ data, itemsPerPage }) => {
  const [currentPage, setCurrentPage] = useState(1);
  const indexOfLastItem = currentPage * itemsPerPage;
  const indexOfFirstItem = indexOfLastItem - itemsPerPage;
  const currentItems = data.slice(indexOfFirstItem, indexOfLastItem);
  const paginate = (pageNumber) => setCurrentPage(pageNumber);
  return (
    <section>
      <ul>
        {currentItems.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
      <footer>
        <button onClick={() => paginate(currentPage - 1)} disabled={currentPage === 1}>
          Página anterior
        </button>
        <button onClick={() => paginate(currentPage + 1)} disabled={indexOfLastItem >= data.length}>
          Página siguiente
        </button>
      </footer>
    </section>
  );
};
export default PaginatedList;

Mejores prácticas y optimización

Aunque el ejemplo que hemos visto basado en React es bastante sencillo, considera usar un backend que soporte la paginación, eso evitará que necesites recibir el array completo de datos para paginarlo en el cliente, evitando descargas de datos innecesarias.

También puedes usar alguna biblioteca específica para paginación, lo que puede ahorrarte tiempo de desarrollo y ofrecer de entrada una paginación con mayores posibilidades de uso y configuración.

¿Cuál es la mejor librería de paginación para React?

Atendiendo a las estrellitas de GitHub una de las principales librerías de paginación para React es React-Paginate. También te recomendamos que evalúes los componentes de paginación de Material-UI.

Implementación de paginación en Laravel

Laravel es un framework PHP muy popular. Puedes usarlo para implementar la parte del backend para un sistema de paginación. El framework ya viene con diversos mecanismos para implementar una paginación sin prácticamente esfuerzo por tu parte.

Configuración de rutas y controladores

Para crear páginas que respondan entregando datos paginados debemos configurar una ruta. En las rutas generalmente llamamos a controladores, que serán los encargados de devolver los datos como respuesta. 

Esta podría ser una posible ruta para obtener los datos de clientes paginados.

Route::get('/clientes', [CustomerController::class, 'index']);

Luego podemos crear el controlador usando Artisan:

php artisan make:controller CustomerController

Uso de Eloquent y Paginación en Laravel

En el controlador podemos usar los métodos de Eloquent para crear las respuestas paginadas.

Para ello, tendremos que implementar el método index() usando alguno de los dos métodos que nos aporta Laravel Eloquent para paginar: paginate() y simplePaginate().

public function index()
{
    // Obteniendo los clientes paginadosç
    $customers = Customer::paginate(10);

    // Otros datos que quieras enviar a la vista
    $pageTitle = 'Lista de Clientes';
    $totalCustomers = Customer::count();

    // Pasando múltiples datos a la vista
    return view('clientes.index')->with([
        'customers' => $customers,
        'pageTitle' => $pageTitle,
        'totalCustomers' => $totalCustomers,
    ]);
}

Personalización de los enlaces de paginación en Laravel

Actualmente los estilos de la paginación laravel los genera usando clases de utilidad de Tailwind. Si necesitas que sea de otra manera, porque no uses Tailwind o porque quieras usar tu propia vista para generar los enlaces de paginación puedes enviarle el nombre de una vista Blade que se encargará de enviar los enlaces de paginación.

{{ $paginator->links(vistas.enlaces-paginacion-personalizados) }}

 Ejemplo práctico de paginación con Laravel

Con lo que hemos aprendido aquí para generar la paginación en Laravel solamente nos queda por mostrar el código de la vista.

Podemos ver un ejemplo sencillo aquí:
<div>
    @foreach ($customers as $customer)
        {{ $customer->name }}
    @endforeach
</div>

{{ $customers->links() }}

Como has podido comprobar, la generación de datos paginados en Laravel es especialmente sencilla.

Implementación de paginación en JavaScript

En JavaScript crear un sistema de paginación puede ser muy similar a lo que hemos comentado con React. Obviamente el desarrollo de React nos ofrece algunas ventajas y facilidades extra, pero los mecanismos serán bastante parecidos en el fondo.

Fundamentos de paginación con JavaScript puro

Vamos a ver cómo podríamos adaptar el ejemplo anterior de React para verlo en JavaScript puro.

const paginate = (data, currentPage, itemsPerPage) => {
    const startIndex = (currentPage - 1) * itemsPerPage;
    const endIndex = startIndex + itemsPerPage;
    return data.slice(startIndex, endIndex);
};

Como puedes ver, en esta ocasión lo que tenemos es una función que se llama paginate(). Cada vez que la llamemos tendremos que enviarle los tres datos básicos que necesitamos, el juego de datos, la página actual y los ítems por página.

const data = ['item 1', 'item 2', '...', 'item 100'];  
const itemsPerPage = 10;
const currentPage = 1;
const paginatedData = paginate(data, currentPage, itemsPerPage);

Manipulación del DOM para mostrar resultados paginados

La parte más compleja cuando trabajamos con Javascript sin el uso de alguna librería de interfaces gráficas es la manipulación del DOM para mostrar los resultados.

En este ejemplo tenemos una función que recibe los ítems y vuelca su contenido sobre un elemento de la página que tiene un id=»itemsContainer».

const renderItems = (items) => {
    const container = document.getElementById('itemsContainer');
    container.innerHTML = '';
    items.forEach(item => {
        const itemElement = document.createElement('div');
        itemElement.textContent = item.name;
        container.appendChild(itemElement);
    });
};

Para invocar esta función simplemente tendríamos que enviarle los datos que nos devuelve la función paginate.

const paginatedData = paginate(data, currentPage, itemsPerPage);
renderItems(paginatedData);

Ejemplos de paginación con bibliotecas populares

Hacer las cosas de manera manual, con Javascript puro y sin basarnos en ninguna librería, puede ser un poco complicado y laborioso. A veces puede resultar más conveniente aplicar alguna librería de paginación para que nos facilite nuestro trabajo.

Podemos usar librerías basadas en jQuery como https://pagination.js.org/ que es un plugin específico para paginar resultados. Nos permitiría realizar un código más compacto y comprensible.

$('#demo').pagination({
    dataSource: [1, 2, 3, '...', 1000],
    callback: function(data, pagination) {
        // Usar nuestro propio template
        var html = template(data);
        // Enviar el resultado a un contenedor
        dataContainer.html(html);
    }
})

Si no usas jQuery te recomendamos buscar componentes de paginación para tu propia librería.

¿Es necesario usar frameworks para implementar paginación en JavaScript?

Como hemos dicho antes, no es necesario crear sistemas de paginación basados en librerías, pero sí puede aportarnos facilidad y productividad.

Por ejemplo, sería perfectamente posible crear nuestro componente de paginación usando Web Components para construir un Custom Element reutilizable que permita paginar cualquier conjunto de datos. Podríamos hacer uso de otras facilidades de Javascript como los template strings para construir plantillas capaces de mostrar los datos paginados o los enlaces de paginación. Obviamente requerirá un poco más de tiempo y conocimientos pero el desarrollo de estas funcionalidades puede resultar hasta entretenido.

Paginación con Bootstrap

Bootstrap es un framework CSS muy popular. En realidad, al ser solamente un recurso basado en CSS solo nos servirá para facilitarnos la labor de mostrar los enlaces para paginación de una manera atractiva, con un mínimo esfuerzo. Es decir, Bootstrap no se mete en la parte de la funcionalidad que tú requieras para conseguir los set de datos paginados.

Integración y personalización con Bootstrap

Para usar Bootstrap simplemente tenemos que incluir los archivos de CSS y Javascript que nos ofrece el framework. Luego necesitamos construir el HTML para nuestra web, usando las clases CSS que proporciona Bootstrap para aplicar estilo a cada parte del código.

Aquí podemos ver el HTML de los enlaces de navegación que hace uso de las clases de Bootstrap:

<nav aria-label='Page navigation example'>
  <ul class='pagination'> 
    <li class='page-item'><a class='page-link' href='#'>Previous</a></li>
    <li class='page-item'><a class='page-link' href='#'>1</a></li>
    <li class='page-item'><a class='page-link' href='#'>2</a></li>
    <li class='page-item'><a class='page-link' href='#'>3</a></li>
    <li class='page-item'><a class='page-link' href='#'>Next</a></li>
  </ul>
</nav>

Uso de componentes de Bootstrap para paginación

Bootstrap nos entrega diversas clases para construir nuestros propios componentes de paginación, con la posibilidad de incorporar elementos como iconos, páginas desactivadas o inhabilitadas, manejar el tamaño de los enlaces y otras cosas.

Te recomendamos consultar la documentación de Bootstrap para paginación y así encontrar un listado completo de todas sus posibilidades. En el siguiente código te mostramos un componente HTML para paginación que usa algunas de las clases extra para personalizar el aspecto del paginador que nos aporta este framework CSS:

<nav aria-label='Page navigation example'>
  <ul class='pagination pagination-lg justify-content-end'>
    <li class='page-item disabled'>
      <a class='page-link' href='#' tabindex='-1'>Previous</a>
    </li>
    <li class='page-item'><a class='page-link' href='#'>1</a></li>
    <li class='page-item'><a class='page-link' href='#'>2</a></li>
    <li class='page-item'><a class='page-link' href='#'>3</a></li>
    <li class='page-item'>
      <a class='page-link' href='#'>Next</a>
    </li>
  </ul>
</nav>

Los enlaces de paginación anteriores serían grandes gracias al uso de «pagination-lg» y estarían alineados a la derecha debido a «justify-content-end».

Estilización y personalización de la paginación en Bootstrap

Si deseamos personalizar los estilos predeterminados que nos ofrece Bootstrap simplemente tenemos que crear nuestro propio archivo de código CSS que se incluya después del propio código de Bootstrap y que sobreescriba los estilos del framework para las clases que hemos visto en el HTML de ejemplos anteriores.

Antes de ver código de ejemplos es importante mencionar que la clave para que nuestros estilos acaben venciendo a los del framework está en dos detalles:

  • Colocar el código CSS propio después de los archivos de CSS de Bootstrap.
  • Usar selectores con la suficiente especificidad, de modo que puedas sobreescribir los estilos definidos por Bootstrap.

Ahora vamos a ver el código CSS personalizado que necesitaríamos para cambiar el estilo con el que se representan los enlaces para la paginación.

.custom-pagination .page-link {
    color: #007bff;
    background-color: #f8f9fa;
    border: 1px solid #dee2e6;
}

.custom-pagination .page-item.active .page-link {
    background-color: #007bff;
    border-color: #007bff;
    color: white;
}

Como ves, a veces los selectores para poder vencer la especificidad se complican bastante. Este es un efecto que dificulta la experiencia de desarrollo pero que ocurre con mucha frecuencia al usar los frameworks CSS basados en componentes.

¿Puedo combinar Bootstrap con otros frameworks para la paginación?

El uso de Bootstrap es perfectamente viable en combinación con otros frameworks, ya sean Javascript o frameworks de backend como Laravel. De hecho es bastante frecuente combinar Bootstrap con React o con Laravel.

Si estás desarrollando con React no tienes que hacer más que incluir Bootstrap en tu proyecto y usar las clases de Bootstrap en los componentes React. React funciona muy bien con los estilos globales definidos en frameworks basados en componentes, por lo que no necesitarás hacer nada en particular para que funcionen en conjunto.

Ya por lo que respecta a Laravel, desde hace unas versiones usa Tailwind de manera predeterminada para crear los estilos de los enlaces de paginación. Es por ello que si deseamos usar Bootstrap necesitamos realizar una pequeña configuración. 

Tenemos que modificar el archivo App\Providers\AppServiceProvider y añadir el siguiente código:

public function boot(): void
{
    Paginator::useBootstrapFive();
}

Si estamos trabajando con la versión 4 de Bootstrap lanzamos tenemos que usar este método:

Paginator::useBootstrapFour();

Mejores prácticas para la paginación

Con las guías fundamentales que hemos abordado en este artículo podrás crear sistemas de paginación en diferentes tecnologías. Solo queremos acabar dando algunos consejos recomendables a la hora de hacer sistemas eficientes y optimizados de cara al rendimiento y el posicionamiento SEO.

Carga eficiente de datos en paginación

Para que la paginación aporte los beneficios de optimización de la carga de datos es necesario basarnos en el backend. Esto nos permitirá que el servidor no necesite entregar al cliente todos los datos completos, sino únicamente los de la página que se esté visualizando.

Esto lo conseguimos fácilmente con frameworks como el mencionado Laravel, pero también podemos usar Symfony basado en PHP o Django basado en Python, por poner un par de ejemplos.

Mantenimiento de la accesibilidad en la paginación

Para hacer que los enlaces de paginación sean más accesibles es importante basarse en etiquetas a, que sean fácilmente identificables y se puedan recorrer mediante el tabulador. Además podemos usar atributos como `aria-label` y `aria-current` para mejorar la accesibilidad de los elementos de paginación.

Optimización SEO en páginas con paginación

La paginación es una buena práctica para SEO, ya que incluir listas de enlaces demasiado grandes puede ser contraproducente. No obstante, es importante llevar en consideración otros aspectos que pueden afectar al SEO de tu sitio web. 

Usar títulos distintos en cada página

Es un error frecuente que todas las páginas del sistema de paginación se llamen igual (tengan el mismo «title»). Eso puede ser contraproducente porque tu sitio tendrá páginas que literalmente se solaparán.

Personaliza el contenido de las páginas de resultados

Igual que hemos comentado con el title de la página, toma en consideración cambiar los encabezados (H1). Trata de personalizar el texto de cada página indicando la información de página actual, número de resultados y número de páginas. 

Coloca atributos que permitan rastrear los enlaces

Para que las páginas de resultados sean rastreables de una manera más sencilla por los motores de búsqueda y usa etiquetas link con los atributos rel=»prev» y rel=»next» asociando las URL siguiente y anterior.

<link rel='prev' href='/page/1'>
<link rel='next' href='/page/3'>

Manejo de errores y estados vacíos en la paginación

Maneja las situaciones especiales en los sistemas de navegación que construyas. Por ejemplo, cuando no haya más que una página no deberían verse los enlaces de siguiente y anterior. O por poner otro ejemplo, en la primera página de resultados, el enlace de «página anterior» no debería verse, o al menos debería estar desactivado.

Fernán García de Zúñiga

Productos relacionados: