React & Frontend

React Fiber: Arquitetura Interna, Reconciliation e Rendering Phases: Do Básico ao Avançado

13 min de leitura

React Fiber: Arquitetura Interna, Reconciliation e Rendering Phases: Do Básico ao Avançado

React Fiber: Arquitetura Interna, Reconciliation e Rendering Phases React Fiber é a reimplementação do mecanismo de rendering do React, introduzida na versão 16. Antes do Fiber, o React usava uma abordagem de pilha de chamadas que renderizava a árvore de componentes de forma síncrona, bloqueando a thread principal e impedindo que o navegador processasse eventos, animações ou outras tarefas importantes. O Fiber resolve esse problema dividindo o trabalho de rendering em pequenas unidades chamadas de fibers, que podem ser pausadas, retomadas e priorizadas. A motivação central do Fiber é permitir incremental rendering — a capacidade de dividir o trabalho de rendering em várias frames, priorizando tarefas mais urgentes e deixando tarefas menos críticas para depois. Isso resulta em uma experiência de usuário significativamente melhor, especialmente em dispositivos com menor poder computacional ou durante períodos de alta atividade. O Modelo Mental do Fiber O que é um Fiber? Um fiber é um objeto JavaScript que representa uma unidade de trabalho. Cada

<h2>React Fiber: Arquitetura Interna, Reconciliation e Rendering Phases</h2>

<p>React Fiber é a reimplementação do mecanismo de rendering do React, introduzida na versão 16. Antes do Fiber, o React usava uma abordagem de pilha de chamadas que renderizava a árvore de componentes de forma síncrona, bloqueando a thread principal e impedindo que o navegador processasse eventos, animações ou outras tarefas importantes. O Fiber resolve esse problema dividindo o trabalho de rendering em pequenas unidades chamadas de fibers, que podem ser pausadas, retomadas e priorizadas.</p>

<p>A motivação central do Fiber é permitir incremental rendering — a capacidade de dividir o trabalho de rendering em várias frames, priorizando tarefas mais urgentes e deixando tarefas menos críticas para depois. Isso resulta em uma experiência de usuário significativamente melhor, especialmente em dispositivos com menor poder computacional ou durante períodos de alta atividade.</p>

<h2>O Modelo Mental do Fiber</h2>

<h3>O que é um Fiber?</h3>

<p>Um fiber é um objeto JavaScript que representa uma unidade de trabalho. Cada componente na árvore do React tem um fiber correspondente. Um fiber contém informações sobre o componente, seu estado, props, filhos e referências para fibers relacionados. Diferentemente da abordagem anterior baseada em pilha, fibers formam uma estrutura ligada (linked structure) que permite ao React pausar, resumir e descartar trabalho sem perder o estado.</p>

<pre><code class="language-javascript">// Estrutura simplificada de um Fiber

const fiber = {

// Tipo do componente

type: MyComponent,

// Props e estado

props: { name: &#039;John&#039; },

state: { count: 0 },

// Referências para outros fibers

parent: parentFiber,

child: childFiber,

sibling: siblingFiber,

// Trabalho associado

effectTag: &#039;UPDATE&#039;, // &#039;PLACEMENT&#039;, &#039;UPDATE&#039;, &#039;DELETION&#039;

effects: [],

// Instância do componente (class components)

instance: componentInstance,

// Hooks e estado funcional

memoizedState: null,

// Versão anterior do fiber (para comparação)

alternate: previousVersionFiber

};</code></pre>

<p>A estrutura de linked fibers é fundamental porque permite que React navegue pela árvore sem depender da pilha de chamadas. A referência <code>alternate</code> é particularmente importante — ela aponta para a versão anterior do fiber, permitindo que React compare o estado anterior com o novo durante a reconciliação.</p>

<h3>Por que uma Linked Structure?</h3>

<p>Quando o React precisava renderizar uma árvore usando recursão (na abordagem anterior), a pilha de chamadas do JavaScript acumulava todas as chamadas recursivas. Se uma renderização demorasse muito (digamos, alguns segundos), nada mais poderia executar na thread principal — nenhum evento seria processado, nenhuma animação seria desenhada. A linked structure elimina essa dependência da pilha e permite que React controle quando pausar e retomar o trabalho.</p>

<h2>Fases de Rendering: Render e Commit</h2>

<p>React divide o processo de rendering em duas fases distintas: <strong>render phase</strong> e <strong>commit phase</strong>. Compreender essa divisão é essencial para entender Fiber.</p>

<h3>Render Phase (Fase de Renderização)</h3>

<p>A render phase é onde React executa a reconciliação — comparando a nova árvore com a anterior, determinando quais componentes precisam de atualizações e criando uma lista de efeitos a serem executados. Durante essa fase, React pode pausar, descartar ou retomar o trabalho a qualquer momento. É seguro repetir essa fase múltiplas vezes porque nenhuma alteração real é feita ainda.</p>

<pre><code class="language-javascript">// Exemplo: componente que pode ter sua renderização pausada/retomada

function Counter() {

const [count, setCount] = React.useState(0);

// Este código executa durante a render phase

console.log(&#039;Rendering component with count:&#039;, count);

const expensiveCalculation = () =&gt; {

let result = 0;

for (let i = 0; i &lt; 1000000000; i++) {

result += Math.sqrt(i);

}

return result;

};

// Este cálculo pesado pode ser entrecortado

const value = expensiveCalculation();

return (

&lt;div&gt;

&lt;p&gt;Count: {count}&lt;/p&gt;

&lt;button onClick={() =&gt; setCount(count + 1)}&gt;

Increment

&lt;/button&gt;

&lt;/div&gt;

);

}</code></pre>

<p>Durante a render phase, React não atualiza o DOM ou chama efeitos colaterais (como <code>useEffect</code>). Se você tentar acessar <code>document.getElementById()</code> ou modificar referências diretas durante o render, o comportamento será impredizível porque a fase pode ser pausada ou repetida.</p>

<h3>Commit Phase (Fase de Commit)</h3>

<p>Após a render phase estar completa, React entra na commit phase — é aqui que as mudanças são realmente aplicadas ao DOM. Diferentemente da render phase, a commit phase é <strong>síncrona e não pode ser interrompida</strong>. React precisa garantir que toda a árvore de DOM seja atualizada de forma consistente em uma única operação.</p>

<pre><code class="language-javascript">function DataFetcher() {

const [data, setData] = React.useState(null);

const [loading, setLoading] = React.useState(true);

React.useEffect(() =&gt; {

// Este código é executado APÓS a commit phase

console.log(&#039;Commit phase completed, now fetching data&#039;);

fetch(&#039;/api/data&#039;)

.then(res =&gt; res.json())

.then(json =&gt; {

setData(json);

setLoading(false);

});

}, []);

return loading ? &lt;p&gt;Loading...&lt;/p&gt; : &lt;pre&gt;{JSON.stringify(data)}&lt;/pre&gt;;

}</code></pre>

<p>A separação entre render e commit phases é o que permite que React priorize trabalho. Se uma atualização urgente chegar (como resposta a um clique do usuário), React pode pausar uma renderização de baixa prioridade (como atualizar uma lista grande) e processar o clique primeiro.</p>

<h2>Reconciliation: O Algoritmo de Comparação</h2>

<h3>O Algoritmo Reconciliation</h3>

<p>A reconciliação é o processo de comparação entre a árvore anterior (representada pelos fibers <code>alternate</code>) e a nova árvore (a que seria renderizada agora). O objetivo é identificar quais nós sofreram mudanças e precisam ser atualizados no DOM.</p>

<p>O React usa heurísticas inteligentes para tornar a reconciliação eficiente:</p>

<ol>

<li><strong>Elementos de tipos diferentes produzem árvores diferentes</strong>: Se o tipo do elemento muda (ex: <code>&lt;div&gt;</code> para <code>&lt;span&gt;</code>), React descarta a árvore antiga e cria uma nova.</li>

</ol>

<ol>

<li><strong>Keys estáveis</strong>: Quando renderizando listas, adicionar keys (chaves) ajuda React a identificar qual item é qual, mesmo que sua posição mude.</li>

</ol>

<ol>

<li><strong>Heurística de profundidade</strong>: React não compara fibers em profundidades diferentes — compara apenas fibers no mesmo nível.</li>

</ol>

<pre><code class="language-javascript"></code></pre>

<h3>Comparação de Fibers</h3>

<p>Quando React entra na render phase, ele compara cada fiber com seu <code>alternate</code> (versão anterior). Se não há <code>alternate</code>, é uma nova inserção. Se há <code>alternate</code> mas as props ou estado mudaram, é uma atualização. Se há <code>alternate</code> mas o tipo mudou, é uma exclusão seguida de uma inserção.</p>

<pre><code class="language-javascript">// Demonstração de como React rastreia mudanças

function Profile({ userId, showBio }) {

const [user, setUser] = React.useState(null);

React.useEffect(() =&gt; {

// Renderização é pausável aqui

fetch(/api/users/${userId})

.then(r =&gt; r.json())

.then(setUser);

}, [userId]);

if (!user) return &lt;p&gt;Loading...&lt;/p&gt;;

return (

&lt;div&gt;

&lt;h1&gt;{user.name}&lt;/h1&gt;

{/ Mudanças nas props (showBio) causam re-rendering /}

{showBio &amp;&amp; &lt;p&gt;{user.bio}&lt;/p&gt;}

{/ React compara esta props com a versão anterior /}

&lt;img src={user.avatar} alt={user.name} /&gt;

&lt;/div&gt;

);

}

// Quando showBio muda de true para false:

// 1. Render phase: React determina que &lt;p&gt; precisa ser removido

// 2. Commit phase: O &lt;p&gt; é removido do DOM

// Tudo sem re-renderizar o componente inteiro</code></pre>

<h2>Priorização e Scheduling: Como React Organiza o Trabalho</h2>

<h3>Níveis de Prioridade</h3>

<p>React classifica atualizações em diferentes níveis de prioridade. Atualizações de cliques de usuários têm prioridade alta, enquanto atualizações de dados em background têm prioridade baixa. O scheduler do React observa se há tempo disponível na thread principal e processa trabalhos de baixa prioridade apenas quando não há trabalho de alta prioridade pendente.</p>

<pre><code class="language-javascript">// Exemplo usando startTransition (React 18+)

function SearchUsers() {

const [query, setQuery] = React.useState(&#039;&#039;);

const [results, setResults] = React.useState([]);

const [isPending, setIsPending] = React.useState(false);

const handleSearch = (e) =&gt; {

const value = e.target.value;

// Atualização urgente: atualizar o input imediatamente

setQuery(value);

// Atualização não urgente: buscar e atualizar resultados

// Pode ser interrompida se o usuário digitar novamente

React.startTransition(() =&gt; {

// Simulação de busca pesada

const filtered = largeDataset.filter(user =&gt;

user.name.includes(value)

);

setResults(filtered);

});

};

return (

&lt;div&gt;

&lt;input

value={query}

onChange={handleSearch}

placeholder=&quot;Search...&quot;

/&gt;

{isPending &amp;&amp; &lt;p&gt;Searching...&lt;/p&gt;}

&lt;ul&gt;

{results.map(user =&gt; (

&lt;li key={user.id}&gt;{user.name}&lt;/li&gt;

))}

&lt;/ul&gt;

&lt;/div&gt;

);

}</code></pre>

<p>Nesse exemplo, a atualização do <code>query</code> é processada imediatamente (alta prioridade), enquanto a filtragem dos <code>results</code> é uma transição (baixa prioridade) e pode ser interrompida. Se o usuário digitar outra letra, React descarta o trabalho anterior de filtragem e começa novamente com a nova query — sem bloquear o input.</p>

<h3>Time Slicing</h3>

<p>Time slicing é a técnica que permite que React interrompa o trabalho de render phase em pequenos intervalos, cedendo tempo para o navegador executar outras tarefas. React usa <code>requestIdleCallback</code> (ou um polyfill) para detectar quando há tempo disponível na thread principal.</p>

<pre><code class="language-javascript">// Este componente renderiza uma lista grande

function LargeList({ items }) {

console.time(&#039;render&#039;);

// Mesmo com muitos itens, a renderização não bloqueia a UI

// porque React a divide em chunks usando time slicing

const renderedItems = items.map(item =&gt; (

&lt;div key={item.id} style={{ padding: &#039;10px&#039;, border: &#039;1px solid gray&#039; }}&gt;

&lt;h3&gt;{item.title}&lt;/h3&gt;

&lt;p&gt;{item.description}&lt;/p&gt;

{/ React pode pausar aqui para processar eventos /}

&lt;/div&gt;

));

console.timeEnd(&#039;render&#039;);

return &lt;div&gt;{renderedItems}&lt;/div&gt;;

}

// Uso com 10.000 itens não trava a UI

function App() {

const items = Array.from({ length: 10000 }, (_, i) =&gt; ({

id: i,

title: Item ${i},

description: Description for item ${i}

}));

return &lt;LargeList items={items} /&gt;;

}</code></pre>

<p>React não renderiza todos os 10.000 itens de uma vez. Em vez disso, ele renderiza alguns, cede controle para o navegador processar eventos ou pintar na tela, depois volta e renderiza mais alguns.</p>

<h2>Conclusão</h2>

<p>Fiber é a arquitetura que tornou React verdadeiramente responsivo e capaz de lidar com interfaces complexas sem travar. Os três pilares para dominar Fiber são: (1) <strong>entender que fibers são objetos JavaScript que formam uma linked structure</strong>, permitindo que React controle quando pausar e retomar o trabalho; (2) <strong>separar mentalmente render phase (pausável, sem efeitos colaterais) de commit phase (síncrona, onde mudanças são aplicadas)</strong>, e (3) <strong>reconhecer que reconciliation é um algoritmo de comparação inteligente</strong> que usa heurísticas como keys estáveis e tipos de elementos para minimizar trabalho desnecessário.</p>

<p>Com esse conhecimento, você entenderá por que certas práticas (como usar index como key) prejudicam performance, e poderá escrever código React mais eficiente e previsível.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://github.com/acdlite/react-fiber-architecture" target="_blank" rel="noopener noreferrer">React Fiber Architecture - Andrew Clark (GitHub)</a></li>

<li><a href="https://react.dev/learn/render-and-commit" target="_blank" rel="noopener noreferrer">React Documentation: Reconciliation</a></li>

<li><a href="https://medium.com/react-in-depth/inside-fiber-in-depth-overview-of-the-new-reconciliation-engine-in-react-e1c04700ef6e" target="_blank" rel="noopener noreferrer">Inside Fiber: in-depth overview of the new reconciliation engine</a></li>

<li><a href="https://www.freecodecamp.org/news/react-fiber-how-the-internals-work/" target="_blank" rel="noopener noreferrer">The Beginner&#039;s Guide to React Fiber</a></li>

<li><a href="https://react.dev/reference/react/useTransition" target="_blank" rel="noopener noreferrer">React 18 Transitions Documentation</a></li>

</ul>

<p>&lt;!-- FIM --&gt;</p>

Comentários

Mais em React & Frontend

Guia Completo de Arquiteturas de Estado em React: Local, Global, Server e URL State
Guia Completo de Arquiteturas de Estado em React: Local, Global, Server e URL State

Introdução: Os Quatro Pilares do Gerenciamento de Estado O gerenciamento de e...

Hooks para Fetch: Abstraindo Ciclo de Requisição, Cache e Retry na Prática
Hooks para Fetch: Abstraindo Ciclo de Requisição, Cache e Retry na Prática

Entendendo o Problema: Por Que Precisamos de Hooks para Fetch Quando começamo...

Como Usar Bundle Analysis em React: Webpack Bundle Analyzer e Tree Shaking em Produção
Como Usar Bundle Analysis em React: Webpack Bundle Analyzer e Tree Shaking em Produção

Entendendo Bundle Analysis e sua Importância Bundle analysis é o processo de...