Capítulo 14
Como o React funciona por baixo
3 min de leitura 464 palavras 1 gravura
Neste capítulo você vai montar um createElement e render mínimos (volume opcional). O projeto-fio é o Ateliê Boa Viagem, ateliê digital fictício em Boa Viagem, Recife.
Antes desta etapa
Opcional. Exige conforto com React dos volumes 02–06.
Seu ponto de partida
Use o exemplo 14-react-por-baixo do pacote anexo e copie inicio/ para uma pasta de prática fora do original. A raiz do exemplo é a referência completa desta etapa.
Use servidor só em 127.0.0.1 quando o README do exemplo pedir HTTP local. Abrir ou testar não publica nada.
Como praticar
Leia → copie ou digite → mude uma coisa → preveja → salve → recarregue → confira. Restaure cada experiência antes da próxima. Faça as atividades antes de abrir as respostas comentadas.
JSX vira chamadas
Por baixo, JSX parece React.createElement(tipo, props, …filhos). Um render mínimo cria nós DOM e anexa na raiz.
Faça na sua cópia
Confira o trecho no contexto do exemplo antes de mudar.
function createElement(type, props, ...children) {
return { type, props: props || {}, children };
}
Mude uma coisa e preveja
Crie um elemento h1 e veja o objeto no console.
Anote o que espera observar antes de salvar e recarregar.
Recarregue e confira
O objeto descreve type e children.
Se não acontecer
Chame createElement manualmente neste volume.

render percorre a árvore
Se type é string, cria elemento. Se filho é texto, cria text node. Props viram atributos (com o cuidado de className).
Faça na sua cópia
Confira o trecho no contexto do exemplo antes de mudar.
function render(vnode, container) {
const el = document.createElement(vnode.type);
container.appendChild(el);
}
Mude uma coisa e preveja
Suporte a texto filho simples.
Anote o que espera observar antes de salvar e recarregar.
Recarregue e confira
O h1 aparece na página.
Se não acontecer
Trate typeof child === ‘string’.
Isto não substitui o React
O objetivo é intuição. Faltam hooks, reconciliação completa e concurrent features. Volte ao eixo do volume depois desta curiosidade.
Faça na sua cópia
Confira o trecho no contexto do exemplo antes de mudar.
opcional ≠ obrigatório para o fechamento
Mude uma coisa e preveja
Se estiver saturado, pule para o volume 15 e volte depois.
Anote o que espera observar antes de salvar e recarregar.
Recarregue e confira
O percurso principal continua sem este volume.
Se não acontecer
Não trave o volume aqui.
Atividades
Atividade 1
JSX é entendido nativamente pelo navegador?
Atividade 2
O que createElement devolve neste mini modelo?
Atividade 3
Este volume é pré-requisito do Node?
Respostas comentadas
Resposta da atividade 1
Não; precisa de transformação (Babel/compilador) ou createElement manual.
Resposta da atividade 2
Um objeto descritor (vnode) com type, props e children.
Resposta da atividade 3
Não; é opcional.
O arquivo completo
Referência do exemplo 14-react-por-baixo, reproduzida aqui para que você possa conferir sem sair da página.
index.html
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Por baixo — Ateliê Boa Viagem</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<a class="skip" href="#conteudo">Ir para o conteúdo</a>
<header>
<p><strong>Ateliê Boa Viagem</strong></p>
<nav aria-label="Principal"><ul class="nav"><li><a href="index.html" aria-current="page">Início</a></li></ul></nav>
</header>
<main id="conteudo">
<h1>Render mínimo</h1>
<div id="raiz"></div>
<script src="mini.js"></script>
</main>
<footer><p>Conteúdo fictício. Estudo em 127.0.0.1.</p></footer>
</body>
</html>
mini.js
function createElement(type, props, ...children) {
return { type, props: props || {}, children };
}
function render(vnode, container) {
if (typeof vnode === 'string' || typeof vnode === 'number') {
container.appendChild(document.createTextNode(String(vnode)));
return;
}
const el = document.createElement(vnode.type);
Object.entries(vnode.props || {}).forEach(([k, v]) => {
if (k === 'className') el.setAttribute('class', v);
else if (k.startsWith('on') && typeof v === 'function') el.addEventListener(k.slice(2).toLowerCase(), v);
else el.setAttribute(k, v);
});
(vnode.children || []).flat().forEach((c) => render(c, el));
container.appendChild(el);
}
const tree = createElement('div', { className: 'card' },
createElement('h2', null, 'Ateliê Boa Viagem'),
createElement('p', null, 'createElement + render mínimos')
);
render(tree, document.getElementById('raiz'));