Virtualizar listas grandes com o CDK do Angular

Torne listas grandes mais responsivas implementando a rolagem virtual.

Stephen Fluin
Stephen Fluin

A lista de rolagem é um dos padrões de interface mais comuns atualmente, seja navegando em um feed com rolagem infinita no seu site de mídia social favorito ou navegando em um painel corporativo. Quando as listas de rolagem se tornam muito longas (centenas, milhares ou centenas de milhares de itens), o desempenho do aplicativo pode ser afetado.

O carregamento de listas grandes pode demorar porque o aplicativo precisa carregar e renderizar todos os dados antecipadamente. A renderização e a navegação também podem ser lentas , porque cada item da lista pode ter dados avançados, mídia e funcionalidade.

Os usuários podem enfrentar problemas ao carregar ou rolar a página, levando à frustração e ao abandono da página.

Rolagem virtual no Angular com o Component Dev Kit

A rolagem virtual é a principal técnica usada para resolver esses problemas de escala. A rolagem virtual dá a impressão de uma lista muito grande — fornecendo uma barra de rolagem de tamanho adequado — e a capacidade de navegar pela lista sem exigir que o aplicativo mantenha a lista inteira na memória ou renderize-a na página.

No Angular, a rolagem virtual é fornecida pelo Component Dev Kit (CDK). Ao modificar o modo de iteração das listas e fornecer alguns parâmetros de configuração adicionais, a rolagem virtual do CDK gerenciará automaticamente a renderização virtual das listas, melhorando o desempenho e a capacidade de resposta da página.

Em vez de renderizar a lista inteira de uma só vez, apenas um subconjunto dos itens que cabem na tela (além de um pequeno buffer) será renderizado. À medida que o usuário navega, um novo subconjunto de itens é calculado e renderizado, reutilizando o DOM atual, se desejado.

O restante desta postagem mostra como configurar a rolagem virtual básica. Confira um exemplo completo neste app de exemplo:

Configurar a rolagem virtual

Primeiro, verifique se você instalou o @angular/cdk usando seu gerenciador de pacotes favorito. Para instalar usando o npm, execute este comando no terminal:

npm install --save @angular/cdk

Adicionar ScrollingModule ao app

Com o CDK instalado, importe ScrollingModule, que processa a rolagem virtual, do pacote @angular/cdk/scrolling. Em seguida, adicione-o à matriz de importações do seu módulo:

import {ScrollingModule} from '@angular/cdk/scrolling';

...
imports: [
  ScrollingModule
...
]
...

Criar uma janela de visualização

Para ver como o pacote funciona, tente criar um componente com uma lista simples de números de 0 a 99.999:

@Component({
  template: `<div *ngFor="let item of list">{{item}}</div>`
})
export class ScrollComponent {
  list = Array.from({length: 100000}).map((_, i) => i);
}

Quando o navegador renderiza o app, ele precisa renderizar 100.000 elementos <div> individuais. Isso pode ser bom para nós de texto simples, mas qualquer complexidade no modelo repetido não será bem dimensionada, e todos os listeners de eventos serão multiplicados significativamente.

Para adicionar rolagem virtual e evitar esses problemas, crie uma janela de visualização envolvendo a lista em um elemento <cdk-virtual-scroll-viewport>:

@Component({
  template: `<cdk-virtual-scroll-viewport>
    <div *ngFor="let item of list">{{item}}</div>
    </cdk-virtual-scroll-viewport>`
})
export class ScrollComponent {
  list = Array.from({length: 100000}).map((_, i) => i);
}

Como ScrollingModule renderiza dinamicamente subconjuntos da lista, é necessário especificar a altura da janela de visualização usando o CSS padrão. Também é necessário dar uma dica à janela de visualização sobre o conteúdo especificando o itemSize. O módulo usa essas informações para determinar quantos itens devem ser mantidos no DOM em um determinado momento e como renderizar uma barra de rolagem de tamanho adequado.

@Component({
  template: `<cdk-virtual-scroll-viewport itemSize="18" style="height:80vh">
    <div *ngFor="let item of list">{{item}}</div>
    </cdk-virtual-scroll-viewport>`
})
export class ScrollComponent {
  list = Array.from({length: 100000}).map((_, i) => i);
}

Por fim, converta *ngFor em *cdkVirtualFor:

@Component({
  template: `<cdk-virtual-scroll-viewport itemSize="18" style="height:80vh">
    <div *cdkVirtualFor="let item of list">{{item}}</div>
    </cdk-virtual-scroll-viewport>`
})
export class ScrollComponent {
  list = Array.from({length: 100000}).map((_, i) => i);
}

Em vez de iterar por toda a lista, a janela de visualização identificará e repetirá dinamicamente o subconjunto correto da lista para o usuário. Agora, quando o usuário carregar a página, o CDK renderizará o subconjunto da lista que cabe na tela (mais um pouco do buffer). Todos os eventos de rolagem na janela de visualização carregarão e renderizarão o subconjunto adequado da lista:

Os subconjuntos de renderização do CDK de uma lista à medida que o usuário rola a tela.

Mais informações

As habilidades de rolagem virtual do CDK vão muito além desse exemplo básico. No app de exemplo, a lista inteira estava na memória, mas ela podia ser buscada sob demanda em aplicativos mais complexos. Saiba mais sobre os outros recursos de ScrollingModule e a diretiva cdkVirtualOf lendo sobre Scrolling na documentação do CDK.

Imagem principal da Mr Cup / Fabien Barral no Unsplash.