Back

Guia completo para rolagem infinita em React

Guia completo para rolagem infinita em React

Rolagem infinita é um padrão de UX onde novo conteúdo é carregado conforme os usuários rolam a página para baixo. Comum em feeds sociais, linhas do tempo e aplicativos de notícias, é uma maneira fluida de explorar grandes conjuntos de dados sem usar botões de paginação. Neste guia, você aprenderá como construir rolagem infinita em React usando tanto uma biblioteca de terceiros quanto um hook personalizado.

Principais Aprendizados

  • Aprenda 2 maneiras práticas de implementar rolagem infinita em React
  • Use um hook personalizado com IntersectionObserver ou um pacote de terceiros
  • Gerencie estados de carregamento, paginação e resultados vazios

O que é rolagem infinita?

Rolagem infinita carrega novos dados conforme o usuário rola próximo ao final de uma lista. Ela elimina a necessidade de paginação e cria uma experiência de navegação contínua. Você verá isso em produtos como Instagram, Twitter e Reddit.

Método 1: Usando um pacote (react-infinite-scroll-component)

A maneira mais fácil de implementar rolagem infinita em React é com um pacote bem testado.

Passo 1: Instalação

npm install react-infinite-scroll-component

Passo 2: Exemplo de uso básico

import InfiniteScroll from 'react-infinite-scroll-component';

function Feed() {
  const [items, setItems] = useState([]);
  const [page, setPage] = useState(1);
  const [hasMore, setHasMore] = useState(true);

  const fetchMoreData = async () => {
    const res = await fetch(`/api/posts?page=${page}`);
    const newItems = await res.json();
    if (newItems.length === 0) setHasMore(false);
    else {
      setItems(prev => [...prev, ...newItems]);
      setPage(prev => prev + 1);
    }
  };

  return (
    <InfiniteScroll
      dataLength={items.length}
      next={fetchMoreData}
      hasMore={hasMore}
      loader={<h4>Loading...</h4>}
      endMessage={<p>No more results</p>}
    >
      {items.map(item => <div key={item.id}>{item.title}</div>)}
    </InfiniteScroll>
  );
}

Prós

  • Rápido de configurar
  • Estados de carregamento e finalização integrados

Contras

  • Menos controle sobre a lógica de rolagem
  • Adiciona dependência de pacote

Método 2: Hook personalizado com IntersectionObserver

Este método oferece controle total e sem dependências extras.

Passo 1: Criar um hook

function useInfiniteScroll(callback, ref) {
  useEffect(() => {
    const observer = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) callback();
    });
    if (ref.current) observer.observe(ref.current);
    return () => observer.disconnect();
  }, [callback, ref]);
}

Passo 2: Usar em um componente

function Feed() {
  const [items, setItems] = useState([]);
  const [page, setPage] = useState(1);
  const [hasMore, setHasMore] = useState(true);
  const sentinelRef = useRef(null);

  const loadMore = async () => {
    if (!hasMore) return;
    const res = await fetch(`/api/posts?page=${page}`);
    const newItems = await res.json();
    if (newItems.length === 0) setHasMore(false);
    else {
      setItems(prev => [...prev, ...newItems]);
      setPage(prev => prev + 1);
    }
  };

  useInfiniteScroll(loadMore, sentinelRef);

  return (
    <div>
      {items.map(item => <div key={item.id}>{item.title}</div>)}
      <div ref={sentinelRef} style={{ height: 1 }} />
    </div>
  );
}

Prós

  • Totalmente personalizável
  • Funciona com qualquer lógica de rolagem ou API

Contras

  • Requer mais configuração
  • IntersectionObserver não é suportado no IE11

Padrões e dicas do mundo real

  • Aplicar debounce nas chamadas de fetch para evitar sobrecarregar as APIs
  • Mostrar um spinner ou loader esqueleto para melhor UX
  • Adicionar lógica de nova tentativa para erros de rede
  • Lidar com casos extremos como zero resultados ou páginas vazias
if (items.length === 0 && !hasMore) {
  return <p>No posts found.</p>;
}

Considerações de desempenho

  • Use bibliotecas como react-window para virtualização ao renderizar milhares de itens
  • Memorize componentes de itens para evitar re-renderizações
  • Limpe os observadores adequadamente para evitar vazamentos de memória
useEffect(() => {
  const observer = new IntersectionObserver(...);
  return () => observer.disconnect();
}, []);

Conclusão

Rolagem infinita é um recurso comum em interfaces modernas. Seja você preferindo a simplicidade de um pacote ou o controle de um hook personalizado, o React torna ambas as abordagens acessíveis. Sempre considere o desempenho e o feedback de carregamento ao implementar rolagem infinita.

Perguntas Frequentes

Usar uma biblioteca como `react-infinite-scroll-component` oferece uma configuração rápida e conveniente.

Defina uma flag `hasMore` como false quando a API retornar um array vazio.

Pode prejudicar, se você estiver renderizando muitos itens. Use ferramentas de virtualização como `react-window` para gerenciar listas grandes.

Use `IntersectionObserver` para acionar o carregamento de dados quando uma `div` inferior (sentinela) entrar no campo de visão.

Listen to your bugs 🧘, with OpenReplay

See how users use your app and resolve issues fast.
Loved by thousands of developers