React e o “DOM” de renderizar componentes com JavaScript

Vica Escorcio
21 Tech
Published in
6 min readOct 4, 2022

Eu sei que você adorou a piada.

Depois de muita luta contra a preguiça e a procrastinação, resolvi documentar meus estudos através de simples e práticos artigos. A ideia é transmitir meu processo de aprendizado (spoiler: é lento para car@$@%) que, em sua maioria, consiste mais em entender causas do que memorizar consequências.

Como primeiro aglomerado de erros gramaticais (artigos escritos por mim), escolhi falar sobre meus estudos em React, especificamente de como essa biblioteca JavaScript manipula o DOM para renderizar componentes em uma página Web.

Antes de mais nada, se você não está familiarizado com os termos JavaScript, DOM e HTML, aconselho perguntar ao "pai google", por mais que estes conceitos sejam brevemente abordados nesse artigo.

JavaScript e o DOM

React é uma biblioteca JavaScript (aqui um ótimo artigo sobre a diferença entre biblioteca e framework), isso quer dizer que esta é um conjunto de classes e módulos que implementam convenções e estruturas a serem usadas em qualquer projeto JS. E dentro dessa perspectiva, nada mais justo entender, primeiro, como a linguagem "pura" consegue renderizar componentes em uma página web. A ideia é entender o princípio por de trás de todas as camadas de abstração que foram acrescentadas pela biblioteca para que a implementação dessa feature fosse mais simples.

Esse código abaixo, por mais simples e horrível, está renderizando um componente em uma página HTML. Mas como ?

...
<div id="container"></div>
<br>
<button id="botao"> Clique aqui! </button>
<script>
document.getElementById('botao').addEventListener('click',
(event) => {
event.preventDefault();
document.getElementById('container').innerHTML =
`<span> Renderizado! </span>`;
}
);
</script>

Você pode acompanhar e testar esse exemplo por aqui.

Simples, manipulando o DOM de uma página web.

E o que é o DOM ? Bom, não vou arruinar, com minha péssima retórica, a ótima definição presente no MDN docs, mas vou chamar atenção para certas partes que nos ajudarão a entender o processo de renderização de componentes:

O Document Object Model (DOM) é uma interface de programação para os documentos HTML e XML. Representa a página de forma que os programas possam alterar a estrutura do documento, alterar o estilo e conteúdo. O DOM representa o documento com nós e objetos, dessa forma, as linguagens de programação podem se conectar à página.

Uma página da Web é um documento. Este documento pode ser exibido na janela do navegador ou como a fonte HTML. Mas é o mesmo documento nos dois casos. O DOM (Document Object Model) representa o mesmo documento para que possa ser manipulado. O DOM é uma representação orientada a objetos da página da web, que pode ser modificada com uma linguagem de script como JavaScript.

Talvez, essa definição estaria melhor, se o segundo trecho estivesse colocado antes do primeiro, né ?

Por ser uma representação orientada a objetos da página, conseguimos manipulá-lo como se fosse um objeto, mudando a sua estrutura que, nesse caso, é composta de nós e mais objetos representando os elementos de uma página.

Representação da estrutura em nós do DOM (Fonte: https://www.hostinger.pt/tutoriais/dom-o-que-e)

Voltando ao código, mas agora em uma versão bem mais simples:

...
<div id="container"></div>
<br>
<script>
document.getElementById('container').innerHTML =
`<span> Renderizado! </span>`;
</script>

Podemos agora ver como esse script renderiza um elemento HTML (span), manipulando o DOM. Ao chamar document, acessamos o objeto que representa a página web, com getElementById, obtém-se o a qual se quer manipular o conteúdo. A partir daí, altera-se o conteúdo HTML desse nó mudando o valor da propriedade innerHTML. Simples, não ?

Você deve está pensando: "React manipula o DOM, certo ?"

maizoumenos.

React e o DOM (Virtual)

Como vimos, é possível manipular o DOM, e consequentemente criar, alterar, estilizar componentes HTML usando JavaScript. Então é lógico pensar que o React faz uso do mesmo mecanismo. Mas nem tudo são flores, e isso tem seus problemas.

Para entender melhor essa problemática da manipulação do DOM, vamos resgatar um trecho da sua definição:

"O DOM representa o documento com nós e objetos".

Á primeira vista, essa característica viabiliza uma interface amigável entre o DOM e as linguagens orientadas a objeto. Conseguimos trazer a representação da página web para o paradigma da tecnologia utilizada. Porém, essa interface acessível não necessariamente implica em performance.

Imagina que vamos trabalhar com a seguinte página web, representada pelo documento abaixo:

...
<div id= "no1">
<div id= "no2">
...
<div id= "no3">
<div id= "no4">
...
<div id= "no5">
<div id= "no6">
...
</div>
</div>
</div>
</div>
</div>
</div>

Nesse exemplo, temos vários nós aninhados. Imagine que queira se atualizar o primeiro nó. Bom, isso é extremamente fácil e direto usando JavaScript. Ao alterar o conteúdo do elemento, o DOM vai renderizá-lo novamente, em um processo que é relativamente mais custoso, pois os nós filhos também serão redesenhados.

Note que para exemplos simples, isso não exigiria tanta perfomance, porém estamos na era das SPA's (Single Page Application). Esses tipos de aplicação demandam atualização de partes da página web de maneira isolada, sem ter que recarregá-la por completo. Então, por mais que se consiga fazer as alterações necessárias com a manipulação direta do DOM, torna-se inviável fazê-lo em uma estrutura cheias de nós e com carga de atualização alta.

Mas como resolver esse problema ? Ora, React, como boa biblioteca que é, acrescenta as camadas de abstrações necessárias para tornar esse processo mais performático.

A solução é até bem simples em seu princípio: ao invés de alterar diretamente o DOM, altera-se uma cópia dele, o Virtual DOM. Uma representação leve em JavaScript do original. Essa representação é criada logo quando novos elementos são adicionados a UI.

Bom, há duas coisas importantes a se falar antes:

  • O acesso ao DOM e sua alteração não são operações lentas, o processo de refletir essas alterações re-renderizando a UI, sim.
  • Quando as alterações são feitas em lote, o re-render da UI é bem mais performático.

React utiliza um padrão de construção de interface gráfica onde os seus elementos são componentes. Cada componente possui um estado que pode ser alterado, e uma vez que é, esses são renderizados novamente pela biblioteca. Mas o grande diferencial aqui é a manipulação no Virtual DOM ao invés do DOM. Isso permite que React faça uma comparação da versão anterior do Virtual DOM com a atual e saiba exatamente o que foi alterado em um processo chamado "diffing". Além disso, todos as alterações no DOM são feitas em lotes. A performance aumenta consideravelmente, uma vez que não estamos alterando o DOM diretamente e engatilhando várias renderizações a cada mudança de conteúdo dinâmico na UI.

fonte: https://www.oreilly.com/library/view/learning-react-native/9781491929049/ch02.html

A mudança do nó no segundo nível implica no cálculo "diff" que tem como resultado a mudança de toda árvore abaixo dele. O DOM só vai trabalhar na renderização do que foi computado como alterado pelo Virtual DOM.

React x JavaScript

Vamos resgatar o código HTML acima com vários nós aninhados. Imagine que queremos atualizar o conteúdo de alguns nós internos. Se fizéssemos com JavaScript simples, poderíamos muito bem usar o seguinte código:

<script>
document.getElementById($id_do_elemento_1).innerHTML = //new
document.getElementById($id_do_elemento_2).innerHTML =
...
document.getElementById($id_do_elemento_3).innerHTML =
</script>

Parece simples, mas péssimo de se escrever. Dependendo da quantidade de elementos a ser alterados, vai ativar várias renderizações da UI (lembre-se: estamos manipulando o DOM diretamente). Porém, vamos supor que você tem o conteúdo de todos os nós. Não seria bem mais fácil alterar o nó de mais alta hierarquia trocando seu conteúdo por completo ?

<script>
document.getElementById($parent_node.innerHTML = html_content_of_all_nodes
</script>

Ainda sim, essa renderização seria nada performática. O custo de desenhar todos os nós é alto. Imagina se for uma parte da aplicação que está constantemente sendo alterada ? Mesmo uma pequena mudança iria engatilhar a renderização de todos os nós.

Ou seja, a estratégia do React nos permite superar esses obstáculos, sabendo:

  • Exatamente o que precisa ser alterado.
  • Alterar em lotes, não em frações.

Cada mudança no conteúdo vai gerar o cálculo do diffing no Virtual DOM, e somente o que foi alterado será re-renderizado pelo DOM.

Fontes:

--

--