DEV Community

Cover image for Criando uma paginação do zero com React usando Hooks
Ivan Trindade
Ivan Trindade

Posted on

Criando uma paginação do zero com React usando Hooks

As aplicações que exibem grandes quantidades de dados na forma de uma lista ou tabela, podem implementar a paginação para dividir os dados em uma sequência de páginas. Em vez de buscar grandes quantidades de dados de uma API do servidor, a paginação carrega dados sob demanda, diminuindo o tempo de carregamento e melhorando a interface do usuário geral.

Embora existam muitas bibliotecas disponíveis para implementar a paginação, algumas são um pouco pesadas, prejudicando o desempenho geral da sua aplicação. Neste artigo, criaremos um componente de paginação reutilizável usando React Hooks.

Como exemplo, exibiremos a lista de passageiros na imagem abaixo, usando paginação.

Imagem de paginação

O que abordaremos neste artigo:

  • Hook useSate
  • Hook useEffect
  • Configurando o projeto
  • Criar um componente de paginação
  • Usando o componente de paginação

Antes de entrar na implementação, deixe-me apresentar dois React Hooks que usaremos neste artigo.

Hook useState

Se você quiser adicionar estado ao seu componente funcional, o Hook UseState fará o trabalho. Considere o exemplo abaixo:

// uma nova variável de estado chamada "currentPage" 
const [currentPage, setCurrentPage] = useState(1);
Enter fullscreen mode Exit fullscreen mode

O useState ajuda a preservar os valores entre as chamadas de função. Leva um único argumento, que é o estado inicial. No exemplo acima, a variável currentPage é definida como padrão 1. O useState retornará um par de valores, sendo o primeiro o estado da variável e o segundo, a função para manipular o estado.

Usaremos o Hook useState para manter o estado da página atual, os limites mínimo e máximo da página, bem como manter os dados de resposta da API do passageiro.

Hook useEffect

Se você quiser executar quaisquer efeitos colaterais, como busca de dados, manipulação de DOM ou inscrição e cancelamento de inscrição em eventos, o useEffect o ajudará a:

useEffect (()=>{ // chama rest api },[]);

Enter fullscreen mode Exit fullscreen mode

O React tem acesso ao estado do seu componente, portanto, ele basicamente lembrará a função que você passou e a invocará após as atualizações do DOM. Usamos o Hook useEffect para buscar dados de passageiros da API REST.

Configurando o projeto

Nosso objetivo é exibir a lista de passageiros com paginação, então usaremos a API REST gratuita para fornecer uma lista de dados de passageiros. Comece criando uma nova aplicação React usando o comando Create React App abaixo:

npx create-react-app pagination-tutorial

Enter fullscreen mode Exit fullscreen mode

Remova todo o conteúdo padrão do arquivo App.js. Incluiremos nossos componentes aqui mais tarde. O arquivo final deve se parecer com o código abaixo:

import './App.css';
function App() {
  return (
    <div className="App">
       <div className="App-header">
           // inclua o componente Passenger, que criamos no final 
            do artigo

        </div>
    </div>
  );
}
export default App;
Enter fullscreen mode Exit fullscreen mode

Agora, podemos executar a aplicação com o comando abaixo:

yarn start
Enter fullscreen mode Exit fullscreen mode

Criando um componente de paginação

O componente funcional permite dividir a interface do usuário em partes independentes e reutilizáveis. Usaremos um componente funcional que possui um único argumento contendo props para o componente. Antes de criar nosso componente de paginação, vamos esclarecer alguns dos poucos termos usados no restante do artigo.

  • Página atual: representa a posição do usuário na página
  • Limite máximo de páginas: representa o limite superior da página
  • Limite mínimo de página: representa o limite inferior da página

Vá para a pasta src e crie um novo arquivo chamado: Pagination.js

import React from 'react';
const Pagination = (props)=> {
    return(
        <div>
        </div>
    )
}
export default Pagination;
Enter fullscreen mode Exit fullscreen mode

Como estamos criando um componente reutilizável para paginação, suponha que o componente obtenha todos os dados do componente pai usando props. Nosso objetivo é criar uma saída como na imagem abaixo:

Imagem de paginação

Inicialize os termos que discutimos na seção anterior:

// init
  const { currentPage, maxPageLimit, minPageLimit} = props;
  const totalPages = props.response.totalPages-1;
  const data = props.response.data;
Enter fullscreen mode Exit fullscreen mode

Agora, para inserir o número total de páginas, criaremos os números das páginas a partir de 1. O limite será baseado nos limites máximo e mínimo de páginas:

Imagem de paginação

Construa o array de páginas, que conterá todos os números desde 1 até o total de páginas:

// construir um array com a quantidade de páginas com base no número total de páginas
    const pages = [];
    for (let i=1; i <= totalPages; i++) {
        pages.push(i);
    }
Enter fullscreen mode Exit fullscreen mode

Para criar a interface do usuário com base no número de páginas que estão dentro dos limites mínimo e máximo de páginas, percorra a array de páginas construída com a etapa acima. Se a condição de interação corresponder á página atual, torne-a ativa:

const pageNumbers = pages.map(page => {
        if(page <= maxPageLimit  && page > minPageLimit) {
            return(
        <li key={page} id={page} onClick={handlePageClick} 
            className={currentPage===page ? 'active' : null}>
            {page}
        </li>
            );
        } else {
            return null;
        }
    }

 );
Enter fullscreen mode Exit fullscreen mode

Em seguida, criaremos reticências ..., que aparecem quando há mais páginas do que a página atual á esquerda ou á direita. Ao clicar nas reticências, o usuário pode ir para o grupo de páginas anterior ou seguinte. Você pode vê-los na imagem abaixo, destacados em verde:

Imagem de paginação verde

// page ellipses
    let pageIncrementEllipses = null;
    if(pages.length > maxPageLimit) {
        pageIncrementEllipses = <li onClick={handleNextClick}>&hellip;</li>
    }
    let pageDecremenEllipses = null;
    if(minPageLimit >=1){
        pageDecremenEllipses = <li onClick={handlePrevClick}>&hellip;</li> 
    }
const renderData = (data)=>{
Enter fullscreen mode Exit fullscreen mode

Vamos renderizar nossos passageiros em um formato de lista. No código abaixo, estou mostrando o ID do passageiro e o nome da companhia aérea utilizada por cada passageiro:

return(
        <ul>
            {data.map((d)=> 
            <li key={d['_id']}> The passenger having id {d['_id'].slice(d['_id'].length-5)} using {d.airline[0].name} airlines</li>)
            }
        </ul>
    )
}
Enter fullscreen mode Exit fullscreen mode

Em seguida, combinaremos todos os elementos da interface do usuário e os retornaremos em nosso componente funcional, junto com os botões Anterior e Próximo.

Ao clicar em Anterior, o usuário navega para a página anterior. Ao clicar em Próximo, o usuário navega para a próxima página. Os elementos da interface do usuário são alinhados da seguinte maneira:

Passengers data
2. Pager
    1. Prev button
    2. Page decrement ellipses
    3. Page numbers with current page selection
    4. Page increment ellipses
    5. Next button

 return (
        <div className="main">
            <div className="mainData">
              {renderData(data)}
            </div>
            <ul className="pageNumbers"> 
               <li>
                   <button onClick={handlePrevClick} disabled={currentPage === pages[0]}>Prev</button>
               </li>
               {pageDecremenEllipses}
                {pageNumbers}
               {pageIncrementEllipses}
                <li>
                   <button onClick={handleNextClick} disabled={currentPage === pages[pages.length-1]}&gt;Next</button>
               </li>
            </ul>
        </div>
    )
Enter fullscreen mode Exit fullscreen mode

Até agora, criamos a IU, que inclui eventos como clique na página, clique anterior e próximo clique. Agora, vamos vincular todos os eventos:

const handlePrevClick = ()=>{
        props.onPrevClick();
    }
    const handleNextClick = ()=>{
        props.onNextClick();
    }
    const handlePageClick = (e)=>{
        props.onPageChange(Number(e.target.id));
    }
Enter fullscreen mode Exit fullscreen mode

Usando o componente de paginação

Agora, vamos navegar até o componente pai, que é o componente Passengers, responsável por buscar os dados do passageiro e definir as props de paginação. Use o componente Pagination criado acima nesse componente.

Para criar o componente Passengers, primeiro inicialize o estado. Você pode consultar as variáveis de estado abaixo. Em termos simples, mostraremos o número de páginas começando do 1 ao 5. Iniciamos os limites mínimo e máximo de páginas com 0 e 5, respectivamente.

Definimos a página atual como 1, o que significa que o usuário estará na primeira página. Definindo os dados do passageiro como um array vazio, determinamos que buscaremos os dados nas próximas etapas. O limite de páginas, 5, informa que mostraremos apenas cinco páginas na UI:

const pageNumberLimit = 5;
  const [passengersData, setData] = useState([]);
  const [loading, setLoading] = useState(true);
  const [currentPage, setCurrentPage] = useState(1);
  const [maxPageLimit, setMaxPageLimit] = useState(5);
  const [minPageLimit, setMinPageLimit] = useState(0);
Enter fullscreen mode Exit fullscreen mode

Quando a página atual mudar, buscaremos os dados do passageiro de nossa API com o Hook useEffect, mantendo-os na variável de estado passagenrsData:

useEffect(()=>{
    setLoading(true);
    fetch(`https://api.instantwebtools.net/v1/passenger?currentPage=${currentPage}&size=5`)
    .then((response) => response.json())
    .then((json) => { setData(json); setLoading(false);});

  },[currentPage]);
Enter fullscreen mode Exit fullscreen mode

A etapa principal dessa paginação completa é atualizar a página mínima, máxima e atual, que são atualizadas na mudança de página, no clique anterior e no próximo clique.

Clique anterior

Suponha que você esteja na sexta página do nosso componente de paginação. Se você clicar no botão Anterior, será direcionado para a quinta página e os limites de página deverão ser redefinidos para 1 e 5.

Para obter o exemplo acima, atualizaremos os limites mínimo e máximo de página, somente se a página anterior não estiver no intervalo de páginas atual. O resto obtido após a divisão da página anterior pelo número de página, deve ser zero.

Imagem de paginação

Por exemplo, considere que o limite máximo de páginas deve ser igual ao limite atual, menos o limite de número de páginas. No nosso exemplo na imagem acima, 10 menos cinco é igual a cinco.

Imagem de paginação

Para o limite mínimo de páginas, subtraímos o limite do número de páginas, pelo limite mínimo atual. Em nosso exemplo, calculamos que seis menos cinco é igual a um. Lembre-se que a página atual, é a página anterior menos 1.

Clique próximo

Exploraremos o clique próximo, como uma alternância do exemplo anterior. Suponha que você esteja na quinta página agora. Clique em Próximo e você deve navegar para a sexta página. Os limites da página devem estar entre 6 e 10.

Assim como no clique anterior, só podemos atingir o cenário acima atualizando o limite mínimo e máximo de páginas. Os limites mínimo e máximo de páginas, são atualizados apenas quando a próxima página é maior que o limite máximo de páginas atual:

Imagem de paginação

Para calcular o limite máximo de páginas, adicionamos o limite máximo atual ao limite de número de páginas. Em nosso exemplo, somamos cinco e cinco para igualar 10.

O limite mínimo de páginas é o limite mínimo atual mais o limite do número de páginas. No nosso exemplo, um mais cinco é igual a seis. A página atual é a página anterior mais uma.

Mudança de página

Ao clicar em qualquer número de página, atualize a página atual para o número específico. Abaixo está o trecho de código para todos os principais eventos:

const onPageChange= (pageNumber)=>{
    setCurrentPage(pageNumber);
  }
  const onPrevClick = ()=>{
      if((currentPage-1) % pageNumberLimit === 0){
          setMaxPageLimit(maxPageLimit - pageNumberLimit);
          setMinPageLimit(minPageLimit - pageNumberLimit);
      }
      setCurrentPage(prev=> prev-1);
   }

  const onNextClick = ()=>{
       if(currentPage+1 > maxPageLimit){
           setMaxPageLimit(maxPageLimit + pageNumberLimit);
           setMinPageLimit(minPageLimit + pageNumberLimit);
       }
       setCurrentPage(prev=>prev+1);
    }
Enter fullscreen mode Exit fullscreen mode

Para criar a UI para passageiros com paginação, vamos combinar todos os atributos necessários e enviá-los como props para o componente de paginação:

const paginationAttributes = {
    currentPage,
    maxPageLimit,
    minPageLimit,
    response: passengersData,
  };
  return(
    <div>
        <h2>Passenger List</h2>
        {!loading ? <Pagination {...paginationAttributes} 
                          onPrevClick={onPrevClick} 
                          onNextClick={onNextClick}
                          onPageChange={onPageChange}/>
        : <div> Loading... </div>
        }
    </div>
)

Enter fullscreen mode Exit fullscreen mode

Agora, construímos os componentes pai e filho. Você está pronto para usar o componente pai em qualquer lugar da aplicação.

Conclusão

Neste tutorial, criamos um componente de paginação enviando a página atual, limite máximo de página, limite mínimo de página e outros eventos de página como props para o componente. Usamos React Hooks para gerenciamento de estado e busca de dados.

Enquanto desenvolvemos nossa aplicação de exemplo em React, você pode aplicar a mesma lógica a qualquer projeto. Espero que você tenha aprendido algo novo! Certifique-se de deixar um comentário se tiver alguma dúvida.

Top comments (0)