Nesta área moderna de páginas da web baseadas em JavaScript, o DOM pode ser uma abstração cara. Sem as ferramentas certas para melhorar o desempenho, uma única alteração de prop em seu aplicativo React pode fazer com que os elementos sejam renderizados desnecessariamente.
Mas mesmo sem o envolvimento do JavaScript, ter uma grande árvore DOM pode tornar suas páginas mais lentas e encha seus Core Web Vitals , sobrecarregando seus solicitações de rede, tempo de execução e desempenho de memória.
Padrões para tamanho de DOM
É importante ter em mente que embora os navegadores possam lidar com árvores DOM maiores, é aconselhável limitar o total Os nós DOM contam até 1.500, a profundidade do DOM até 32 e a contagem dos nós DOM para um único elemento pai até 60.
Podemos acabar com um tamanho DOM excessivo enviando um arquivo HTML considerável sobre o fio ou gerando elementos em tempo de execução até excedermos o desempenho orçamentos.
Usando no estado em que se encontra, rolagem infinita e paginação como alternativas à virtualização
Ao exibir um grande conjunto de dados, há muitas maneiras de implementar a visualização. As formas mais notáveis de renderizar o conjunto de dados são por meio da forma como está, paginação ou rolagem infinita.
Podemos visualizar essas três opções da seguinte forma:
Quando nós Se tivéssemos conteúdo contínuo, como vários parágrafos, em nossa página, usaríamos a estratégia”no estado em que se encontra”para renderizar nosso conteúdo. Para otimizar o desempenho de nossa página, recorremos à propriedade de visibilidade de conteúdo CSS. Veja esta postagem do blog para mais detalhes.
No entanto, usar a visibilidade do conteúdo ajudaria apenas na renderização inicial. Quando rolamos a página para baixo até as áreas que o navegador ignorou a renderização, acabamos com uma página que se move lentamente novamente.
O mesmo é verdadeiro para a rolagem infinita. A diferença é que só solicitamos o conteúdo conforme necessário. No entanto, eventualmente enfrentaremos os mesmos problemas de desempenho lento.
A paginação, por outro lado, é a maneira de renderizar com melhor desempenho. Ele exibe apenas o conteúdo necessário na renderização inicial, solicita o conteúdo conforme necessário e o DOM nunca incha com conteúdo desnecessário.
Mas, a paginação é um padrão que não é adequado para exibir todos os grandes conjuntos de dados em uma página da web. Em vez disso, podemos usar virtualização.
O que é virtualização?
A virtualização é um conceito de renderização que se concentra em rastrear a posição do usuário e apenas comprometer o que é visualmente relevante para o DOM em qualquer posição de rolagem. Essencialmente, ele nos fornece todos os benefícios da paginação junto com a UX da rolagem infinita.
Para virtualizar uma lista, pré-calculamos a altura total de nossa lista usando as dimensões dos itens de lista fornecidos e multiplicando pela contagem dos itens da nossa lista.
Em seguida, posicionamos os itens para criar uma lista que o usuário possa percorrer. Posicionar nossos elementos corretamente é a chave para a eficiência da virtualização porque itens individuais podem ser adicionados ou removidos sem afetar outros itens ou causar refluxo (ou seja, o processo de recalcular a posição de um elemento na página).
No entanto, há outra maneira de renderizar dados.
Como virtualizar uma grande lista usando react-window
Para implementar a virtualização, usaremos react-windo , que é uma reescrita de react-virtualized. Você pode ler uma comparação entre as duas bibliotecas aqui .
Para instalar o react-window, execute o seguinte:
$ yarn add react-window # a biblioteca $ yarn add-D @ types/react-window # autocompletar
react-window será instalado como uma dependência, enquanto os tipos para ele serão instalados como um devDependency, mesmo que não estejamos usando TypeScript. Também precisaremos de faker.js para gerar nosso grande conjunto de dados.
$ yarn add faker
Em nosso App.js, iremos importar faker, bem como useState, e inicializar nosso estado de dados com a função address.city do faker. Em nosso código, ele criará um array com comprimento de 10000.
import React, {useState} from”react”; import * como faker de”faker”; const App=()=> {const [data, setData]=useState (()=> Array.from ({length: 10000}, faker.address.city)); return (
- {data.map ((city, i)=> (
- {cidade}
))}
); };
Em seguida, inicializamos lentamente nosso estado usando uma função para otimizar para desempenho . Em seguida, tornamos nossa lista rolável, atribuindo a ela uma largura e uma altura e definindo overflowY para rolar.
Para comparar o desempenho com e sem virtualização, adicionaremos um botão reverso que inverte nossa matriz de dados.
const App=()=> {const [data, setData]=useState (()=> Array.from ({length: 10000}, faker.address.city)); const reverse=()=> {setData ((dados)=> data.slice (). reverse ()); }; return (
- {data.map (( cidade, i)=> (
- {city}
))}
); };
Veja a Caneta
Lista não virtualizada no React de Simohamed (@smhmd )
em CodePen .
Agora, tente o botão reverso e observe como a atualização está latente.
Para virtualizar esta lista, usaremos FixedSizeList do react-window.
import {FixedSizeList as List} da”janela de reação”; const App=()=> {const [data, setData]=useState (()=> Array.from ({length: 10000}, faker.address.city)); const reverse=()=> {setData ((dados)=> data.slice (). reverse ()); }; return ( {( {index, style})=> {return (
);}} ); };
Podemos usar FixedSizeList de várias maneiras. Neste caso, estamos criando um array imaginário com o mesmo comprimento de nossos dados (por meio de itemCount) e usando-o para indexar nossos dados.
Os filhos de FixedSizeList expõem um suporte de renderização que tem cada índice e os estilos necessários (estilos de posicionamento absolutos, etc.) passados para ele.
Nós também podemos ser explícitos e passar nossos dados e recebê-los na propriedade de renderização por meio de itemData, assim:
{({data, index, style})=> {return
; }}
Observe que nossos estilos inline anteriores foram substituídos por suportes de largura e altura. overflowY é controlado pela prop de layout, que é padronizada como vertical.
É importante passar o argumento da prop de renderização de estilo para o elemento mais externo (o li, em nosso caso). Sem ele, todos os elementos serão empilhados uns sobre os outros e não haverá nada para percorrer.
Os elementos FixedSizeList renderizam dois elementos de invólucro que são padronizados para divs e podem ser personalizados usando innerElementType e outerElementType./p>
Em nosso caso, definimos innerElementType como ul por motivos de acessibilidade. No entanto, apenas adereços predefinidos podem ser usados. Adicionar adereços como role ou data-* não terá nenhum efeito.
Por padrão, FixedSizeList usará os índices de dados como chaves React. Mas porque estamos modificando nosso array de dados, devemos usar valores únicos para nossas chaves. Para isso, FixedSizeList expõe a propriedade itemKey, que assume uma função que deve retornar uma string ou um número. Usaremos a função datatype.uuid do faker.
; }} {({dados, índice, estilo})=> {retornar
Veja a Caneta
Lista virtualizada no React de Simohamed ( @smhmd )
em CodePen .
Como mencionei, podemos comparar instantaneamente nossa lista virtualizada com a lista não virtualizada usando o botão reverso. Mas as otimizações de desempenho não param por aí. Se tivermos um elemento caro que renderizamos para cada item da lista em vez de nosso único li, a react-window nos permite renderizar uma interface do usuário simples ao rolar.
Para fazer isso, primeiro precisamos habilitar o isScrolling booleano passando useIsScrolling para nosso FixedSizeList.
{({index, style, isScrolling})=> isScrolling? (
;
Veja como isso poderia ser:
Veja a caneta
React Window’s isScrolling de Simohamed ( @smhmd )
em CodePen .
Como virtualizar uma grade com react-window
Agora que sabemos como para virtualizar uma lista, vamos aprender a virtualizar uma grade. É um processo semelhante, mas a diferença é que você tem que adicionar a contagem e as dimensões dos seus dados em ambas as direções: verticalmente (colunas) e horizontalmente (linhas).
import {FixedSizeGrid as Grid} de”react-window”; import * como faker de”faker”; const COLUNAS=18; const ROWS=30; dados const=Array.from ({comprimento: ROWS}, ()=> Array.from ({comprimento: COLUNAS}, faker.internet.avatar)); function App () {return (;}}
Veja a Caneta
React Window Grid de Simohamed (@smhmd )
em CodePen .
Fácil, certo?
Conclusão
Neste artigo, cobrimos os limites de desempenho do DOM e também como otimizar um DOM enxuto usando várias estratégias de renderização. Também discutimos como a virtualização, por meio do uso de react-window, pode exibir com eficiência grandes conjuntos de dados para atender às nossas metas de desempenho.