Pular para o conteúdo
Cursos

DevClub

LógicaFront-endBack-endMobile

IA Club

IA na prática
Estudar programaçãoEstudar IA
LiçãoIniciantecódigo testado

O que é React: componentes, estado e para que serve

O que é React, o problema que os componentes resolvem e o que muda em relação ao DOM puro — com o mesmo contador escrito das duas formas.

Rodolfo Mori16 min de leitura

São 8h05 numa clínica veterinária. Um pet chegou, e a recepcionista precisa atualizar a fila, a próxima senha e o formulário. Se cada pedaço da página for controlado separadamente, é fácil esquecer um e mostrar informações diferentes.

Esse problema cresce em carrinhos, agendas e painéis, nos quais o mesmo dado aparece em vários lugares. Com o contador, o botão “Chegou um pet” e a lista de senhas da clínica, você verá onde React entra e qual trabalho ele evita.

O que é React e para que ele serve?

React é uma biblioteca de JavaScript para construir e atualizar interfaces. Uma biblioteca é um conjunto de ferramentas prontas; interface é a parte do produto que a pessoa vê e usa, como botões, campos, listas e mensagens.

JavaScript é a linguagem que dá lógica e comportamento à página. React não é outra linguagem: ele organiza esse JavaScript em componentes, pedaços da tela descritos por funções que podem ser combinados e reaproveitados. Função é um bloco de instruções ao qual damos um nome para usá-lo quando necessário.

Pense no painel de senhas: a recepcionista informa a fila atual, não quais pontos da tela devem acender. React segue essa lógica. O limite da analogia é que o painel físico apenas exibe; um componente executa JavaScript, recebe dados e produz uma descrição.

Esse jeito de trabalhar é chamado de declarativo: o código declara como a tela deve ficar. O caminho oposto é imperativo: o código manda criar um elemento, anexá-lo e trocar seu texto passo a passo. Os dois contadores a seguir deixam essa diferença visível.

Comece pela versão sem biblioteca. O DOM é a árvore de objetos que o navegador cria para representar o HTML, a marcação que organiza a página. Um objeto agrupa dados e ações sob uma referência. Você pode aprofundar o DOM na lição sobre o que é DOM. Neste teste, jsdom é um pacote que simula essa árvore dentro do Node.js, programa que executa JavaScript fora do navegador. Assim, o exemplo roda no terminal, a janela em que você dá comandos de texto ao computador, e mostra o HTML final:

js
import { JSDOM } from 'jsdom';

const dom = new JSDOM('<div id="painel"></div>');
const document = dom.window.document;

let naFila = 0;

const painel = document.getElementById('painel');
const contagem = document.createElement('p');
const botao = document.createElement('button');
botao.textContent = 'Chegou um pet';
painel.append(contagem, botao);

function desenhar() {
  contagem.textContent = `${naFila} pets na fila`;
}

botao.addEventListener('click', () => {
  naFila = naFila + 1;
  desenhar();
});

desenhar();
botao.click();
botao.click();

console.log(painel.innerHTML);
<p>2 pets na fila</p><button>Chegou um pet</button>

O import traz JSDOM; new JSDOM(...) cria um documento apenas com a div, e dom.window.document dá acesso a ele. Essas linhas montam o navegador simulado.

let naFila = 0 guarda o dado inicial. let cria uma variável cujo valor pode mudar. Depois, getElementById encontra o painel, e os dois createElement criam um parágrafo e um botão. textContent escreve o texto do botão; append coloca parágrafo e botão dentro do painel.

A função desenhar leva naFila ao parágrafo. addEventListener registra o clique, um evento — ação percebida pela página. A função de seta aumenta o número e redesenha. A primeira chamada mostra zero, os dois botao.click() levam o valor a dois e o log imprime o HTML final.

Funciona, mas repare no trabalho: você cria cada elemento, coloca cada um no lugar certo, guarda a referência de contagem e lembra de chamar desenhar() sempre que naFila muda. O dado está num lugar, a tela está em outro, e manter os dois sincronizados é responsabilidade sua. Se surgir uma segunda contagem, você terá de sincronizá-la também.

Agora a mesma coisa em React:

jsx
import { useState } from 'react';
import { renderToStaticMarkup } from 'react-dom/server';

function PainelDaFila() {
  const [naFila, setNaFila] = useState(2);

  return (
    <div id="painel">
      <p>{naFila} pets na fila</p>
      <button onClick={() => setNaFila(naFila + 1)}>Chegou um pet</button>
    </div>
  );
}

console.log(renderToStaticMarkup(<PainelDaFila />));
<div id="painel"><p>2 pets na fila</p><button>Chegou um pet</button></div>

Os imports trazem useState, que guarda um valor entre atualizações, e renderToStaticMarkup, que transforma a descrição em HTML. Este teste compara a saída no terminal; ele não tenta clicar no botão React.

function PainelDaFila() cria o componente. A linha com useState(2) guarda o estado atual da fila: naFila é o valor, que começa em dois, e setNaFila é a função usada para pedir uma mudança. Estado é a memória do componente, isto é, um dado que pode mudar e influenciar o que aparece.

O return usa JSX, sintaxe parecida com HTML escrita no JavaScript. As chaves inserem naFila; onClick pede o próximo valor; e a última linha renderiza <PainelDaFila /> e imprime o HTML.

O conteúdo final é equivalente ao da primeira versão. O que mudou é quem escreve o passo a passo. No DOM puro, você manda criar, anexar e atualizar. No React, você descreve a tela em função de naFila; não há uma linha sua dizendo “troque o texto do parágrafo”.

Essa diferença tem nome: a primeira é imperativa, a segunda é declarativa.

Experimente você mesmo: preveja a contagem

No primeiro exemplo, naFila começa em zero e recebe dois cliques. Preveja o número final e qual seria o resultado sem um dos cliques. Depois imagine useState(5) no exemplo React: qual trecho do HTML mudaria? Confira no código somente depois de responder.

Até aqui, você já sabe: a versão imperativa explica cada alteração ao DOM; a versão declarativa descreve a interface para o estado atual. React assume o trabalho de manter essas duas coisas em sintonia.

O que é um componente React?

Um componente React é uma função que devolve a descrição de uma parte da interface. Ele pode receber dados, produzir JSX e ser combinado com outros componentes para formar uma tela completa.

A frase “componente é uma função” pode soar como metáfora, mas não é. No teste a seguir, ele é chamado diretamente, como qualquer outra função JavaScript, para revelar o valor devolvido:

jsx
function Senha({ numero, pet }) {
  return <li>Senha {numero}{pet}</li>;
}

const resultado = Senha({ numero: 12, pet: 'Bidu' });

console.log(typeof Senha);
console.log(resultado);
function { '$$typeof': Symbol(react.transitional.element), type: 'li', key: null, props: { children: [ 'Senha ', 12, ' — ', 'Bidu' ] }, _owner: null, _store: {} }

function Senha({ numero, pet }) cria o componente e separa os dados recebidos. Esse objeto de entrada se chama props. O return devolve um li, e as chaves inserem número e pet no texto.

A chamada direta guarda o retorno em resultado; os logs mostram o tipo da função e o valor produzido. A saída prova que Senha é function e devolve um objeto com type e props: um elemento React, descrição da tela, não HTML. Em uma interface, prefira <Senha /> para React controlar seu ciclo.

E o <li> dentro do JavaScript? Isso é JSX, sintaxe que o compilador — a ferramenta que traduz código — transforma antes da execução. Veja a tradução:

js
import { transformSync } from 'esbuild';

const jsx = `
function Senha({ numero, pet }) {
  return <li>Senha {numero} — {pet}</li>;
}
`;

const saida = transformSync(jsx, { loader: 'jsx', jsx: 'transform' });
console.log(saida.code);
function Senha({ numero, pet }) { return /* @__PURE__ */ React.createElement("li", null, "Senha ", numero, " \u2014 ", pet); }

transformSync, importado do esbuild, traduz o texto guardado em jsx. loader: 'jsx' identifica a sintaxe, jsx: 'transform' escolhe a tradução e o log imprime saida.code. O <li> vira React.createElement(...): JSX é açúcar de sintaxe, uma escrita mais amigável para JavaScript equivalente. Na saída, \u2014 é apenas o travessão escapado. O restante está em JSX no React.

Essa regra não dá erro: ela dá silêncio, que é pior. Com a inicial minúscula, o React acredita que você quer uma tag:

jsx
import { renderToStaticMarkup } from 'react-dom/server';

function senha() {
  return <li>Senha 12 — Bidu</li>;
}

console.log(renderToStaticMarkup(<senha />));
<senha></senha>

A função minúscula devolveria um item se fosse chamada, mas <senha /> é lido como tag do navegador. Por isso o renderizador imprime <senha></senha> e nunca chama a função. Se um componente sumir sem erro, confira a inicial primeiro.

Experimente você mesmo: encontre a letra que muda tudo

Antes de alterar o exemplo, faça uma previsão: o que deveria sair se o nome da função e o nome dentro das tags começassem com S maiúsculo? Depois compare sua resposta com o exemplo anterior de Senha. A estrutura pode continuar igual; é a inicial que comunica ao JSX “isto é um componente”.

Até aqui, você já sabe: componente é função, props são o objeto de dados recebido, JSX vira chamadas JavaScript e a letra maiúscula distingue um componente de uma tag da plataforma.

Como o React atualiza a tela sem apagar tudo?

React produz uma nova descrição, compara-a com a anterior e aplica ao DOM apenas as diferenças necessárias. No navegador, o pacote react-dom é o renderizador que transforma essa descrição em elementos visíveis e mantém a tela atualizada.

Renderizador é a ponte entre a descrição React e o lugar onde ela aparecerá. Quando o estado muda, o componente roda novamente, mas isso não significa que todos os elementos reais serão destruídos. O diagrama mostra o ciclo completo:

estado (naFila) componente é chamado React compara com a anterior DOM setNaFila dispara o ciclo de novo

A parte que quase ninguém explica é por que isso importa na prática. A alternativa ingênua para “redesenhar a tela quando o dado muda” é jogar innerHTML de novo. Veja o que acontece quando a recepcionista já tinha digitado o nome do pet no campo:

js
import { JSDOM } from 'jsdom';

const dom = new JSDOM('<div id="app"></div>');
const app = dom.window.document.getElementById('app');

let naFila = 2;

function desenharTudo() {
  app.innerHTML = `
    <p>${naFila} pets na fila</p>
    <input placeholder="nome do pet">
  `;
}

desenharTudo();

const pAntes = app.querySelector('p');
const inputAntes = app.querySelector('input');
inputAntes.value = 'Bidu';   // a recepcionista digitou

naFila = naFila + 1;
desenharTudo();

console.log('texto agora:            ', app.querySelector('p').textContent.trim());
console.log('mesmo <p> de antes?     ', pAntes === app.querySelector('p'));
console.log('mesmo <input> de antes? ', inputAntes === app.querySelector('input'));
console.log('valor digitado:         ', JSON.stringify(app.querySelector('input').value));
texto agora: 3 pets na fila mesmo <p> de antes? false mesmo <input> de antes? false valor digitado: ""

O início cria o DOM e localiza app. naFila começa em dois; desenharTudo substitui seu innerHTML, a marcação interna, por parágrafo e campo. A primeira chamada desenha; as referências guardam os elementos e value = 'Bidu' simula a digitação. Depois a fila aumenta e toda a marcação é substituída.

Os logs comparam texto, elementos e valor. === verifica se duas referências apontam para o mesmo objeto. Os false provam que parágrafo e campo nasceram de novo; "" prova que “Bidu” sumiu. Numa tela real, também se perderiam foco e posição de rolagem.

Agora o mesmo cenário em React, rodando dentro do mesmo jsdom:

jsx
import { JSDOM } from 'jsdom';
import { useState, act } from 'react';
import { createRoot } from 'react-dom/client';

const dom = new JSDOM('<div id="app"></div>');
globalThis.window = dom.window;
globalThis.document = dom.window.document;
globalThis.IS_REACT_ACT_ENVIRONMENT = true;

let chegouUmPet;

function PainelDaFila() {
  const [naFila, setNaFila] = useState(2);
  chegouUmPet = () => setNaFila((n) => n + 1);

  return (
    <div>
      <p>{naFila} pets na fila</p>
      <input placeholder="nome do pet" />
    </div>
  );
}

const app = document.getElementById('app');
await act(() => createRoot(app).render(<PainelDaFila />));

const pAntes = app.querySelector('p');
const inputAntes = app.querySelector('input');
inputAntes.value = 'Bidu';   // a recepcionista digitou

await act(() => chegouUmPet());

console.log('texto agora:            ', app.querySelector('p').textContent);
console.log('mesmo <p> de antes?     ', pAntes === app.querySelector('p'));
console.log('mesmo <input> de antes? ', inputAntes === app.querySelector('input'));
console.log('valor digitado:         ', JSON.stringify(app.querySelector('input').value));
texto agora: 3 pets na fila mesmo <p> de antes? true mesmo <input> de antes? true valor digitado: "Bidu"

JSDOM cria o mesmo documento; as atribuições a globalThis, objeto global do ambiente, entregam ao React a janela, o documento e a configuração do teste. Isso só é necessário porque o exemplo roda no Node.

let chegouUmPet reserva um nome para a ação que o teste chamará. Dentro de PainelDaFila, useState(2) cria o estado, e a função atribuída a chegouUmPet usa setNaFila((n) => n + 1). Nessa escrita, React entrega o valor anterior como n, e a função devolve o próximo. O retorno descreve parágrafo e campo sem dizer como substituí-los.

createRoot(app).render(...) monta o componente, e act espera cada atualização. O teste guarda as referências, digita “Bidu”, chama chegouUmPet e repete os logs. Agora ambos os === são true: React muda apenas o texto, preserva o input e mantém o valor digitado.

É essa comparação que as pessoas chamam de reconciliação (ou “virtual DOM”). O nome assusta mais do que a ideia: comparar dois objetos JavaScript é barato, mexer no DOM é caro, então o React compara antes de mexer.

A função que guarda o dado e dispara esse ciclo é o useState, que tem lição própria em useState no React.

Até aqui, você já sabe: executar o componente novamente não significa recriar todo o DOM. React compara descrições e preserva os elementos que não precisam ser substituídos, inclusive o campo em que a pessoa estava digitando.

React funciona sem navegador?

Sim. Um componente devolve uma descrição em objetos JavaScript, e um renderizador de servidor pode transformar esses objetos em HTML. Por isso React também pode produzir marcação no Node, sem abrir uma janela do navegador.

No exemplo, dois componentes — um usando o outro — viram HTML direto no terminal. Agora a clínica tem três senhas, com dados concretos de pet e tutor:

jsx
import { renderToStaticMarkup } from 'react-dom/server';

function Senha({ numero, pet, tutor }) {
  return (
    <li>
      Senha {numero}{pet} (tutor: {tutor})
    </li>
  );
}

function PainelDaFila({ fila }) {
  return (
    <section>
      <h2>Fila de atendimento</h2>
      <ol>
        {fila.map((item) => (
          <Senha key={item.numero} {...item} />
        ))}
      </ol>
      <p>{fila.length} pets esperando</p>
    </section>
  );
}

const fila = [
  { numero: 12, pet: 'Bidu', tutor: 'Ana' },
  { numero: 13, pet: 'Nina', tutor: 'Carlos' },
  { numero: 14, pet: 'Tobias', tutor: 'Rita' },
];

console.log(renderToStaticMarkup(<PainelDaFila fila={fila} />));
<section><h2>Fila de atendimento</h2><ol><li>Senha 12 — Bidu (tutor: Ana)</li><li>Senha 13 — Nina (tutor: Carlos)</li><li>Senha 14 — Tobias (tutor: Rita)</li></ol><p>3 pets esperando</p></section>

O import traz o renderizador. Senha recebe três props e devolve um li; PainelDaFila recebe fila, um array — lista JavaScript — e devolve seção, lista e total. Dentro de ol, map transforma cada objeto num Senha; key identifica o item e o spread {...item} repassa seus campos como props.

A constante fila guarda os três objetos. A última linha entrega o array ao componente e imprime o HTML. A saída confirma o reaproveitamento de Senha e o resumo de três pets usando apenas recursos comuns de JavaScript.

Por que aparece “Objects are not valid as a React child”?

Esse erro aparece quando o JSX recebe um objeto inteiro no lugar de um conteúdo que consegue mostrar. React não sabe se deve exibir o nome, a espécie ou outra propriedade; você precisa escolher o campo desejado.

Como { } aceita expressões JavaScript, é natural pensar que aceita qualquer valor. O exemplo entrega o objeto completo pet ao elemento li:

jsx
import { renderToStaticMarkup } from 'react-dom/server';

const pet = { nome: 'Bidu', especie: 'cachorro' };

function Senha() {
  return <li>Senha 12 — {pet}</li>;
}

console.log(renderToStaticMarkup(<Senha />));
/private/tmp/clinica/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:6474 throw Error( ^

Error: Objects are not valid as a React child (found: object with keys {nome, especie}). If you meant to render a collection of children, use an array instead. at retryNode (/private/tmp/clinica/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:6474:17) at renderNodeDestructive (/private/tmp/clinica/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:6367:11) at renderNode (/private/tmp/clinica/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:6905:18)

Node.js v24.16.0

pet tem as propriedades nome e especie, mas Senha tenta renderizar o objeto inteiro. A mensagem aponta as duas chaves: escolha {pet.nome} ou, para uma lista, transforme o array com map. Números, textos e arrays podem aparecer; um objeto derruba a renderização. Uma função gera o aviso Functions are not valid as a React child e não aparece.

Experimente você mesmo: use a mensagem como pista

Leia found: object with keys {nome, especie} e preveja qual campo produziria “Bidu” e qual produziria “cachorro”. Só depois confira a declaração de pet. Esse treino transforma a mensagem de erro em mapa para o dado correto.

Onde o React roda: navegador, servidor ou celular?

React participa de interfaces no navegador, no servidor e em aplicativos Android ou iOS. A biblioteca descreve componentes e estado; um renderizador transforma essa descrição no resultado adequado a cada ambiente.

Por isso os exemplos importam react para componente e estado, e react-dom para produzir a tela ou o HTML.

pacote onde roda o que produz
react-dom/client navegador elementos de verdade no DOM da página
react-dom/server Node, no servidor uma string de HTML, pronta para enviar
react-native Android e iOS componentes nativos do sistema

A parte que você aprende — componente, prop, estado — é a mesma nos três. Muda o alvo. Foi por isso que o PainelDaFila do início rodou no terminal, sem navegador: era o renderizador de servidor trabalhando.

React é linguagem ou framework?

React não é uma linguagem e também não entrega sozinho tudo o que uma aplicação precisa. Ele é uma biblioteca focada em descrever componentes e manter a interface sincronizada com os dados.

Um framework oferece uma estrutura mais ampla e costuma definir várias partes da aplicação. React escolhe um foco menor: a interface.

Três mal-entendidos que economizam tempo se você resolver agora:

  • Não é uma linguagem. É uma biblioteca escrita em JavaScript, instalada como qualquer outra dependência. Você continua escrevendo JavaScript.
  • Não é um framework completo. Ele não traz rotas, que ligam endereços às telas; não traz cliente HTTP, usado para pedir dados a um servidor; e não traz validação de formulário pronta. Para compartilhar estado entre partes distantes ele oferece o Context, uma forma básica de disponibilizar o mesmo dado a vários componentes. Cada uma dessas peças é uma escolha sua, e uma opção comum para rotas é o React Router.
  • Não é obrigatório para “ser front-end”. Front-end é a parte visível e interativa de um produto digital. React aparece em muitos produtos e bases de código, por isso vale a pena conhecê-lo, mas resolve um problema específico: interfaces que mudam muito e compartilham estado entre vários pedaços.

O que preciso saber de JavaScript antes de aprender React?

Você precisa entender funções, arrays, objetos e módulos JavaScript o suficiente para reconhecer o que o componente faz. React combina essas peças; ele não substitui a base da linguagem.

Muita dificuldade atribuída ao React é dificuldade de JavaScript com roupa nova. A lista curta do que precisa estar firme é:

  • função e retorno, porque componente é isso;
  • arrow function, a forma curta com =>, porque aparece no onClick;
  • desestruturação, que retira campos de um objeto, e spread, que copia ou repassa esses campos, porque é assim que muitas props chegam e viajam;
  • map, filter e find, ferramentas de arrays usadas para transformar, filtrar e localizar itens de uma lista;
  • módulos import/export, que permitem usar em um arquivo o que foi disponibilizado por outro;
  • operador ternário e &&, formas de escolher se um trecho deve aparecer.

Se três ou mais itens dessa lista estiverem tremidos, volte para eles antes. Sai mais barato do que decorar receita de React.

Quando React é exagero para o seu problema?

React pode ser exagero quando a página quase não muda e o JavaScript necessário é pequeno. A biblioteca acrescenta arquivos e conceitos; o benefício aparece quando a interface tem várias partes reagindo aos mesmos dados.

Esse preço é mensurável. O contador da fila aparece agora nas duas versões como arquivo de entrada de uma página — a versão React monta a tela com createRoot:

jsx
import { useState } from 'react';
import { createRoot } from 'react-dom/client';

function PainelDaFila() {
  const [naFila, setNaFila] = useState(0);
  return (
    <div>
      <p>{naFila} pets na fila</p>
      <button onClick={() => setNaFila(naFila + 1)}>Chegou um pet</button>
    </div>
  );
}

createRoot(document.getElementById('app')).render(<PainelDaFila />);

Os dois import trazem estado e renderização no navegador. O componente começa com zero, mostra a contagem e liga o botão à atualização. Na última linha, getElementById('app') encontra o contêiner da página, createRoot entrega esse espaço ao React e render coloca PainelDaFila nele.

A versão sem biblioteca é a mesma do começo do artigo, agora sem o jsdom e pendurada no mesmo <div id="app"> que o React usa: num arquivo que a página carrega, o document já existe e não precisa ser simulado.

js
let naFila = 0;

const painel = document.getElementById('app');
const contagem = document.createElement('p');
const botao = document.createElement('button');
botao.textContent = 'Chegou um pet';
painel.append(contagem, botao);

function desenhar() {
  contagem.textContent = `${naFila} pets na fila`;
}

botao.addEventListener('click', () => {
  naFila = naFila + 1;
  desenhar();
});

desenhar();

Aqui naFila também começa com zero. O código encontra o mesmo app, cria o parágrafo e o botão, encaixa os elementos e define desenhar. O evento de clique aumenta a variável e chama a função; a chamada final faz o primeiro desenho. É o mesmo resultado, com a sincronização escrita manualmente.

Para comparar o peso enviado ao navegador, as duas versões foram empacotadas com esbuild. Empacotar é reunir o código da aplicação e suas dependências em arquivos próprios para publicação. O teste usou modo de produção na mesma máquina:

bash
npx esbuild app-react.jsx --bundle --minify --format=esm --jsx=automatic \
  --define:process.env.NODE_ENV='"production"' --outfile=bundle-react.js

npx esbuild app-vanilla.js --bundle --minify --format=esm \
  --outfile=bundle-vanilla.js
bundle-react.js 189.7kb

⚡ Done in 15ms

bundle-vanilla.js 246b

⚡ Done in 1ms

npx executa uma ferramenta sem exigir um comando global. Nos dois comandos, --bundle reúne as dependências, --minify remove caracteres desnecessários e --format=esm escolhe módulos JavaScript modernos. A versão React também usa --jsx=automatic para transformar JSX e define o ambiente como produção. Cada --outfile escolhe o nome do arquivo final.

A saída mostra tamanho e tempo de cada empacotamento. kb significa quilobytes, uma medida de dados: o arquivo React ficou com 189,7 kb antes da compressão, e o arquivo de JavaScript puro ficou com 246 bytes. Byte é uma unidade pequena de armazenamento; mais bytes normalmente significam mais dados para baixar.

Comprimido com gzip -9, que é a ordem de grandeza do que trafega até o navegador, são 60.476 bytes contra 207 bytes. Quase 300 vezes mais peso para desenhar o mesmo contador. (MacBook, Node 24.16.0, React 19.2.8, esbuild 0.28.2.)

Esse número não é argumento contra React — é argumento contra usar React em qualquer coisa. Numa tela de um botão só, esse peso é praticamente o aplicativo inteiro. Numa agenda de clínica com formulário, filtro, lista viva e cinco pedaços de tela lendo o mesmo dado, ele se dilui, e você recebe de volta em organização e em bug que não acontece.

Um critério prático para decidir:

o que você está construindo pense em
página institucional, blog, landing page HTML e CSS, com JavaScript pontual
um formulário isolado numa página que já existe JavaScript puro no DOM
painel, agenda, carrinho, área logada React
produto com site e aplicativo móvel React na web e React Native no celular

Até aqui, você já sabe: React traz um custo inicial de arquivos e conceitos. Esse custo faz sentido quando a interface precisa coordenar muitas mudanças; em uma página simples, HTML, CSS e um pouco de JavaScript podem resolver melhor.

Como começar a estudar React na prática?

Comece criando um projeto local e vendo um componente aparecer no navegador. Depois, avance por JSX, props, estado, eventos e listas, sempre mudando uma coisa por vez e prevendo o resultado antes de executar.

Você já sabe o que React faz e por que ele existe. O passo seguinte é ter um projeto rodando na sua máquina, e isso é uma lição só: criar projeto React com Vite. Depois dela, o JSX deixa de ser mágica e vira sintaxe. Se quiser ver a ordem inteira de estudo antes de começar, o guia de React mostra onde cada assunto entra.

Prefere aprender em vídeo?

Tem uma aula sobre este assunto no nosso canal.

Ver todos os vídeos do canal
  • react
  • componentes
  • front-end
  • jsx
  • iniciante

Perguntas frequentes

Componente de classe ainda funciona no React?
Funciona. O React 19 renderiza class Senha extends Component sem reclamar, e projeto antigo está cheio disso. O que mudou é o padrão: a documentação, os hooks e as bibliotecas novas assumem componente em função. Aprenda função primeiro e leia classe quando encontrar.
Preciso saber JavaScript antes de aprender React?
Precisa. Componente é função, prop é parâmetro, lista de tela é map. Quem pula essa base fica decorando receita de React e trava no primeiro problema que a receita não cobre.
Qual a diferença entre React e React Native?
A parte que descreve componentes e estado é a mesma biblioteca. O que muda é o renderizador: no navegador o react-dom cria elementos HTML, no React Native um renderizador próprio cria componentes nativos de Android e iOS.
Dá para colocar React em uma página que já existe?
Dá. O react-dom monta a interface dentro de um elemento que você escolhe, e o resto da página segue como está. É assim que muitos projetos antigos migram por partes, uma tela de cada vez.

Dúvidas e comentários

Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.

Todo o código deste artigo foi executado em Node 24.16.0 com React 19.2.8 e jsdom 30, e as saídas exibidas são as reais — como produzimos este conteúdo.

Fontes consultadas

  1. React — Describing the UI — react.dev
  2. React — Render and Commit — react.dev
  3. MDN — Getting started with React — developer.mozilla.org

Continue por aqui