Pular para o conteúdo
murad.guide

Aplicações Web

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 mínimo

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'));