Renderização no React.js - Guia Completo (passo a passo)
Profile picture

Junior Alves

Senior Developer

Foto: Unsplash

Atualizado: 14 de agosto de 2025 às 07:54

Leitura: 10 minutos de leitura

Criado: 11 de agosto de 2025

Renderização no React.js - Guia Completo (passo a passo)

É por isso que o time do React.js não usa mais o termo "Virtual DOM"

Introdução

Nota

Esse talvez seja o post mais complexo que já escrevi sobre o React.js, então espero que eu consiga te ajudar entender como as coisas acontecem de fato.

Por isso eu conto com a sua ajuda, no final do post, deixe um feedback, para eu saber se o post te ajudou de alguma forma, pois é um conteúdo mais denso que dificilmente encontramos material sobre.

Desde já, valeu demais! Agora bora para o post 🚀

Se você trabalha com React há algum tempo, useState e useEffect são como velhos amigos.
Você sabe que ao chamar setCounter(c => c + 1), a mágica acontece e o número na tela se atualiza.
Mas o que realmente acontece nesse intervalo? Que caminho exatamente seus dados percorrem desde a chamada de uma função até se transformarem em pixels na tela do usuário?
A resposta é um mecanismo muito engenhoso chamado Fiber Reconciler.

Neste post, vamos entender o que acontece "por de baixo dos panos", e explorar a sala de máquinas do React e desvendar o processo de renderização passo a passo.
Entenderemos o que são as árvores current, work-in-progress e a "nova árvore de elementos", e por que essa "nova" arquitetura, que lembra a renderização de um videogame, tornou o React tão poderoso e performático.

Veja em Vídeo ⏯️

O Mundo Antes do Fiber - A Era do Stack Reconciler (O Jogo Single-Player)

Antes do React 16 (lá por 2017), o motor do React era o Stack Reconciler. Seu funcionamento era mais simples de entender: síncrono e recursivo.

Imagine que sua aplicação é um videogame dos anos 90, rodando em um único thread. Quando uma atualização de estado ocorria, era como se o jogo precisasse carregar um novo nível. O que acontecia?

  1. O jogo pausava completamente. A tela congelava.
  2. O processador trabalhava arduamente, de forma ininterrupta, para carregar todos os assets do novo nível.
  3. Só depois de tudo pronto, o jogo voltava a rodar.

O Stack Reconciler funcionava assim. Ao receber uma atualização, ele começava a percorrer sua árvore de componentes (o Virtual DOM) de forma recursiva, chamando a função render de cada um para descobrir o que mudou. Todo esse processo acontecia de uma vez só, na main thread do Javascript.
Se a sua árvore de componentes fosse grande e complexa, a thread principal ficava bloqueada. O resultado? Animações travadas, inputs do usuário com atraso e uma experiência geral "engasgada" (o famoso "jank"). Era um jogo estritamente single-player: enquanto o React estivesse "pensando", o navegador não podia fazer mais nada.

A Chegada do Fiber - Concurrent Mode (O Upgrade para Multiplayer Cooperativo)

O time do React percebeu que, para criar UIs fluidas e complexas, esse modelo "bloqueante" não era sustentável. A solução não foi otimizar o antigo motor, mas reescrevê-lo do zero. Assim nasceu a Arquitetura Fiber, o motor padrão do React desde a versão 16.

A ideia central do Fiber é tornar a renderização assíncrona e interruptível.

Continuando nossa analogia, é como se o nosso jogo single-player recebesse um upgrade para um modo multiplayer cooperativo. Agora, temos dois jogadores:

  • Jogador 1: O Navegador (responsável por animações, eventos do usuário, etc.).
  • Jogador 2: O React (responsável por calcular as atualizações da UI).

Com o Fiber, o React pode "trabalhar" em uma atualização por um tempo (digamos, 5 milissegundos) e então, voluntariamente, ceder o controle de volta ao Navegador. O Navegador pode então verificar se o usuário digitou algo ou se alguma animação precisa ser atualizada. Depois, o React retoma seu trabalho de onde parou. Eles trabalham em cooperação para manter o jogo (sua aplicação) rodando a 60 frames por segundo.

Essa capacidade de pausar, retomar e priorizar o trabalho é o grande diferencial do Fiber. E ele consegue fazer isso através de uma estrutura de dados engenhosa chamada fibra (fiber), que representa uma "unidade de trabalho".

Nota

Nó fiber VS Virtual DOM

Embora intimamente relacionados, o Virtual DOM e um nó Fiber servem a propósitos fundamentalmente diferentes na arquitetura do React. O primeiro é a descrição, enquanto o segundo é a unidade de trabalho.

Pense no Virtual DOM como a planta baixa de uma construção e no nó Fiber como o cronograma detalhado e o status da tarefa de um operário específico naquela construção.

Vou detalhar mais abaixo.

O Roteiro da Renderização - As Duas Fases do Fiber

O trabalho do Fiber é dividido em duas fases principais, como a produção de um filme: a pré-produção, onde tudo é planejado, e a estreia, onde o resultado é exibido ao público.

Fase 1: A Pré-Produção (Render/Reconciliation Phase)

Esta é a fase onde todo o trabalho pesado e inteligente acontece. É assíncrona e interruptível. O diretor (React) pode planejar, replanejar e até jogar fora o roteiro sem que o público (usuário) perceba.

Nesta fase, temos três "atores" principais em cena:

  1. A "Planta Baixa" (A Nova Árvore de Elementos): Quando um setState é chamado, seus componentes re-renderizam e geram uma nova árvore de elementos React (o que conceitualmente chamamos de Virtual DOM). Esta é a planta baixa, o roteiro de como a UI deveria se parecer.

  2. O "Set de Filmagem" Atual (current Tree): Esta é a árvore de fibras que representa a UI que está atualmente na tela. É a foto do que o usuário está vendo agora. O React a trata como imutável durante esta fase.

  3. O "Rascunho da Próxima Cena" (work-in-progress Tree): Para evitar modificar o "set atual", o React cria um rascunho. É aqui que a próxima cena é montada.

O processo de diffing acontece aqui.
O React, como um diretor meticuloso, compara a "Planta Baixa" (nova árvore de elementos) com o "Set Atual" (current tree). O resultado dessa comparação é a construção do "Rascunho da Próxima Cena" (a work-in-progress tree), com anotações de tudo que precisa mudar (atores que entram, saem, mudam de posição, etc.).

Nota

A current tree é comparada com a Virtual DOM (nova árvore de elementos) e o resultado é a work-in-progress tree.

diff(current, vDOM) = current.

Como esta fase não toca no DOM real, o React pode fazê-la em pedaços, pausar se um evento mais importante chegar (como a digitação do usuário), e retomar depois.

Fase 2: A Estreia (Commit Phase)

Quando o "Rascunho da Próxima Cena" (work-in-progress tree) está completo, o diretor grita "Ação!". Esta fase é síncrona e ininterruptível.

Neste momento, o React pega a lista final de mudanças que ele calculou e as aplica de uma só vez no DOM real. É um processo rápido e atômico para garantir que o usuário não veja uma UI inconsistente. É também nesta fase que os efeitos (useEffect) e certos ciclos de vida (como componentDidMount) são executados.

Double Buffering

A forma como o React gerencia as árvores current e work-in-progress é uma adaptação de uma técnica clássica de computação gráfica chamada double buffering, muito usada em videogames.

  • O Front Buffer (o que o jogador vê) é a nossa current tree.
  • O Back Buffer (onde o próximo frame é desenhado secretamente) é a nossa work-in-progress tree.

O React "desenha" a próxima UI inteira no back buffer. Quando tudo está pronto, durante a Fase de Commit, ele instantaneamente "troca" os buffers: a work-in-progress tree é promovida e se torna a nova current tree, e a antiga é descartada. Isso garante que as atualizações sejam sempre fluidas e sem "rasgos" (tearing) visuais.

Dica

💡 Gostou de otimizar seu código? Otimize sua vida profissional também.

Enquanto você se aprofunda nos detalhes do React, deixe que o nosso parceiro, Contador Direto for Devs, cuide da complexidade da sua contabilidade. Eles oferecem um serviço sensacional e descomplicado para desenvolvedores, liberando seu tempo para o que realmente importa: a tecnologia.

Logo Contador Direto

Exemplo Prático em TypeScript

Vamos ver isso em um cenário do dia a dia: uma lista de produtos que pode ser filtrada por um campo de busca.

ProductList.tsx (Componente Filho Memoizado)

import React from 'react';
 
interface Product {
  id: number;
  name: string;
}
 
interface ProductListProps {
  products: Product[];
}
 
// Usamos React.memo para evitar re-renderizações se a lista de produtos não mudar.
export const ProductList = React.memo(({ products }: ProductListProps) => {
  console.log("ProductList renderizou!");
  return (
    <ul>
      {products.map(product => (
        <li key={product.id}>{product.name}</li>
      ))}
    </ul>
  );
});

StorePage.tsx (Componente Pai)

import React, { useState, useMemo } from 'react';
import { ProductList } from './ProductList';
 
const allProducts = [
  { id: 1, name: 'Notebook Gamer' },
  { id: 2, name: 'Mouse Gamer' },
  { id: 3, name: 'Teclado Mecânico' },
  { id: 4, name: 'Monitor Ultrawide' },
];
 
export default function StorePage() {
  const [searchTerm, setSearchTerm] = useState('');
 
  // Filtramos a lista de produtos
  const filteredProducts = useMemo(() => {
    console.log("Calculando filtro...");
    return allProducts.filter(p => 
      p.name.toLowerCase().includes(searchTerm.toLowerCase())
    );
  }, [searchTerm]);
 
  console.log("StorePage (Pai) renderizou!");
 
  return (
    <div>
      <input
        type="text"
        placeholder="Buscar produto..."
        onChange={e => setSearchTerm(e.target.value)}
        value={searchTerm}
      />
      <ProductList products={filteredProducts} />
    </div>
  );
}

O que acontece quando você digita no campo de busca?

  1. Trigger: O onChange chama setSearchTerm. Uma atualização é agendada.
  2. Render Phase (Início): O React inicia uma nova renderização para StorePage. Ele cria uma work-in-progress tree como cópia da current.
  3. Nova Árvore de Elementos: StorePage executa. O hook useMemo é recalculado porque sua dependência (searchTerm) mudou. Uma nova array filteredProducts é criada.
  4. Diffing: O React compara o novo elemento <ProductList /> com o nó de fibra correspondente na current tree. Ele vê que a prop products mudou (porque filteredProducts é uma nova referência de array). A checagem do React.memo permite a re-renderização de ProductList.
  5. Render Phase (Continuação): O React continua o diffing dentro de ProductList, comparando os <li> e usando as keys para determinar eficientemente quais itens foram adicionados, removidos ou mantidos.
  6. Commit Phase: A Fase de Renderização termina. O React então, de forma síncrona, atualiza o DOM para refletir a nova lista de <li>. A work-in-progress tree se torna a nova current tree.

React Internal Interview 📚

Qual foi a principal limitação do Stack Reconciler (usado antes do React 16) que a arquitetura Fiber foi projetada para resolver?

1 / 5

Conclusão

Entender a arquitetura Fiber não é apenas um exercício acadêmico. Saber que a Fase de Renderização é interruptível nos ajuda a entender por que a concorrência é possível e como ferramentas como startTransition funcionam. Saber sobre o double buffering nos dá uma apreciação pela resiliência e fluidez que o React nos oferece.

Da próxima vez que você chamar um setState, lembre-se desta complexa coreografia: a criação da planta baixa, a comparação com o set atual, a construção do rascunho no back buffer e, finalmente, a grande estreia no DOM.

Curtiu? Compartilhe esse post:

Todos os direitos reseverdos © Junior Alves 2025