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.