Virtualizar listas grandes com o CDK do Angular

Implemente a rolagem virtual para tornar listas grandes mais responsivas.

Stephen Fluin
Stephen Fluin

A lista de rolagem é um dos padrões de interface mais comuns hoje em dia, seja para navegar em um feed de rolagem infinita na sua rede social favorita ou em um painel empresarial. Quando as listas de rolagem ficam muito longas (centenas, milhares ou centenas de milhares de itens), a performance do aplicativo pode ser afetada.

Listas grandes podem ser lentas para carregar porque o aplicativo precisa carregar e renderizar todos os dados antecipadamente. Elas também podem ser lentas para renderizar e navegar porque cada item na lista pode ter dados avançados, mídia e funcionalidade.

Os usuários podem ter problemas ao carregar ou rolar a página, o que leva à 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. Ela 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 a renderize na página.

No Angular, a rolagem virtual é fornecida pelo Component Dev Kit (CDK). Ao modificar a maneira como você itera as listas e fornecendo alguns parâmetros de configuração adicionais, a rolagem virtual do CDK gerencia automaticamente a renderização virtual das suas listas, melhorando a performance e a capacidade de resposta da página.

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

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

Como 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 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 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 básicos, mas qualquer complexidade no modelo repetido não é bem escalonada, e todos os listeners de eventos serão multiplicados significativamente.

Para adicionar a rolagem virtual e evitar esses problemas, é necessário criar 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 com CSS padrão. Você também precisa dar à janela de visualização uma dica sobre o conteúdo dela especificando o itemSize. O módulo usa essas informações para determinar quantos itens manter 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 a lista inteira, a janela de visualização identifica e itera dinamicamente o subconjunto correto da lista para o usuário. Agora, quando o usuário carrega a página, o CDK precisa renderizar o subconjunto da lista que cabe na tela (mais um pouco de buffer), e todos os eventos de rolagem na janela de visualização carregam e renderizam o subconjunto apropriado da lista:

O CDK renderiza subconjuntos de uma lista à medida que o usuário rola.

Indo mais longe

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