

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?
- O jogo pausava completamente. A tela congelava.
- O processador trabalhava arduamente, de forma ininterrupta, para carregar todos os assets do novo nível.
- 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:
-
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. -
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. -
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.

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?
- Trigger: O
onChange
chamasetSearchTerm
. Uma atualização é agendada. - Render Phase (Início): O React inicia uma nova renderização para
StorePage
. Ele cria umawork-in-progress
tree como cópia dacurrent
. - Nova Árvore de Elementos:
StorePage
executa. O hookuseMemo
é recalculado porque sua dependência (searchTerm
) mudou. Uma nova arrayfilteredProducts
é criada. - Diffing: O React compara o novo elemento
<ProductList />
com o nó de fibra correspondente nacurrent
tree. Ele vê que a propproducts
mudou (porquefilteredProducts
é uma nova referência de array). A checagem doReact.memo
permite a re-renderização deProductList
. - Render Phase (Continuação): O React continua o diffing dentro de
ProductList
, comparando os<li>
e usando askeys
para determinar eficientemente quais itens foram adicionados, removidos ou mantidos. - 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>
. Awork-in-progress
tree se torna a novacurrent
tree.
React Internal Interview 📚
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.
💡 Quer aprender mais sobre Next.js?
Confira meus cursos práticos e aprenda a criar aplicações profissionais do zero.
Ver CursosCurtiu? Compartilhe esse post: