Guia completo
React: o guia completo para aprender depois do JavaScript
O que é React, o que estudar em cada etapa, onde as pessoas travam e quando não usar React — o mapa da trilha por quem ensina isso todo dia.
React é uma biblioteca de JavaScript para construir interface. Você descreve como a tela deve ficar para cada estado dos dados, e o React se encarrega de mexer no HTML. É um próximo passo comum para quem já consegue escrever pequenas interfaces em JavaScript sem apoio.
Este guia é o mapa da trilha: o que estudar, em que ordem, onde as pessoas travam e — a parte que quase ninguém escreve — quando não usar React. Todos os exemplos são de uma agenda de clínica veterinária: consultas, pets, tutores. O código foi executado no Node 24.16.0 com React 19.2.8, e a saída embaixo de cada bloco é a que apareceu no terminal. Os cinco exemplos que precisam de um navegador rodam dentro do jsdom — um DOM de mentira feito em Node —, e as linhas que montam esse DOM falso são as mesmas nos cinco, então ficaram fora dos blocos para não repetir.
Um painel que você redesenha no papel antes de tocar na parede
Quando a agenda da clínica muda, você não quer escrever uma sequência de ordens como “apague esta linha, mova aquela placa, pinte o contador”. Você quer entregar uma nova versão do painel para os dados atuais e deixar alguém aplicar apenas as diferenças. Esse é o problema central que React assume.
O nome técnico é renderização declarativa baseada em componentes e estado. Você descreve a árvore desejada; React compara versões e atualiza o DOM. No primeiro exemplo do guia, identifique qual dado mudou, qual componente voltou a executar e qual parte do HTML final ficou diferente. Essa sequência é o modelo mental que sustenta o restante da trilha.
O problema é manter a tela coerente com os dados. Parece banal até a segunda tela do projeto.
Veja a agenda da clínica escrita com DOM puro, sem biblioteca nenhuma. Existem duas coisas na página: um resumo com o total de consultas confirmadas e a lista das consultas. Um tutor liga e confirma o horário do Thor, e você atualiza o dado e o item da lista:
// a página tem só isto: <p id="resumo"></p><ul id="lista"></ul>
const consultas = [
{ id: 1, pet: 'Amora', status: 'confirmada' },
{ id: 2, pet: 'Thor', status: 'aguardando' },
];
function desenhar() {
document.querySelector('#lista').innerHTML = consultas
.map((c) => `<li>${c.pet} — ${c.status}</li>`)
.join('');
document.querySelector('#resumo').textContent =
`${consultas.filter((c) => c.status === 'confirmada').length} confirmadas`;
}
desenhar();
// o tutor do Thor liga e confirma: atualizo o dado e o item da lista
consultas[1].status = 'confirmada';
document.querySelector('#lista').children[1].textContent = 'Thor — confirmada';
console.log('resumo:', document.querySelector('#resumo').textContent);
console.log('lista :', [...document.querySelectorAll('#lista li')].map((li) => li.textContent).join(' | '));A lista diz que as duas estão confirmadas. O resumo insiste em uma. Ninguém escreveu um bug: faltou lembrar de atualizar o segundo lugar que dependia do mesmo dado. Com três lugares, você esquece dois. Com uma tela inteira, você esquece sempre.
Agora o mesmo caso em React. Você não atualiza a tela: você troca o dado e descreve, uma vez só, como a tela sai de qualquer dado:
import { renderToStaticMarkup } from 'react-dom/server';
function Agenda({ consultas }) {
const confirmadas = consultas.filter((c) => c.status === 'confirmada');
return (
<section>
<p>{confirmadas.length} confirmadas</p>
<ul>
{consultas.map((c) => (
<li key={c.id}>
{c.pet} — {c.status}
</li>
))}
</ul>
</section>
);
}
const antes = [
{ id: 1, pet: 'Amora', status: 'confirmada' },
{ id: 2, pet: 'Thor', status: 'aguardando' },
];
const depois = antes.map((c) => (c.id === 2 ? { ...c, status: 'confirmada' } : c));
console.log(renderToStaticMarkup(<Agenda consultas={antes} />));
console.log(renderToStaticMarkup(<Agenda consultas={depois} />));As duas linhas são o mesmo componente renderizado com renderToStaticMarkup,
antes e depois de trocar o status do Thor. O resumo e a lista mudaram juntos
porque os dois nascem do mesmo array. É isso, e só isso, que o React faz de
essencial. O resto é ecossistema.
E o que ele não resolve: React não é framework completo. Ele não traz rota, não traz requisição HTTP, não traz formulário validado, não traz autenticação e não traz opinião sobre pasta. Cada uma dessas decisões continua sua. Quem entra esperando um Rails do front-end sai frustrado na primeira semana.
Quanto de JavaScript é pré-requisito de verdade
A resposta honesta é: menos do que dizem, e mais do que você quer. Não é a linguagem inteira — é um recorte pequeno que aparece em toda linha de React.
Este script não tem uma única importação de React, e ainda assim é literalmente o que um componente faz por dentro:
const consultas = [
{ id: 1, pet: 'Amora', status: 'confirmada', tutor: { nome: 'Ana', telefone: '11 99999-0001' } },
{ id: 2, pet: 'Thor', status: 'aguardando', tutor: { nome: 'Bruno' } },
{ id: 3, pet: 'Nina', status: 'confirmada', tutor: { nome: 'Carla', telefone: '11 99999-0003' } },
];
// desestruturação + template literal
const linha = ({ pet, tutor }) => `${pet} (${tutor.nome})`;
// filter + map: é isso que vira lista na tela
console.log(consultas.filter((c) => c.status === 'confirmada').map(linha));
// optional chaining + nullish: campo que pode não existir
console.log(consultas.map((c) => c.tutor?.telefone ?? 'sem telefone'));
// spread: trocar um item sem alterar o array original
const atualizado = consultas.map((c) => (c.id === 2 ? { ...c, status: 'confirmada' } : c));
console.log(atualizado[1].status, consultas[1].status);
console.log('mesma referência?', atualizado === consultas);
// curto-circuito com && : é o "if" do JSX
const alerta = consultas.length > 2 && 'agenda cheia';
console.log(alerta);Repare na terceira linha da saída: atualizado[1] virou confirmada e
consultas[1] continua aguardando. O map com spread produziu um array novo
sem tocar no original. Guarde essa frase — ela reaparece na seção de erros, e é
o motivo número um de tela que não atualiza.
Se essas cinco construções ainda são estranhas, pare aqui e volte para o guia de JavaScript. Aprender React antes disso não é mais rápido: você troca uma dificuldade que tem nome por uma que parece mágica.
O que não é pré-requisito: this, protótipos, classes, closures em
profundidade, geradores, Proxy. Você vai usar closure o tempo todo sem
precisar saber que se chama assim.
O mapa da trilha: das props ao estado compartilhado
A ordem abaixo é a da trilha de React, e ela não é a ordem da documentação oficial. É a ordem em que os assuntos param de doer.
| etapa | o que você aprende | o que consegue fazer no fim |
|---|---|---|
| 1. Componente e JSX | função que devolve marcação, chaves para interpolar | uma tela estática montada em pedaços |
| 2. Props | passar dado de cima para baixo, children |
um cartão de consulta reaproveitado com dados diferentes |
| 3. Listas e condicional | map com key, &&, ternário |
a agenda inteira, ainda sem interação |
4. Eventos e useState |
onClick, onChange, estado que dispara re-render |
confirmar uma consulta e ver a tela mudar |
| 5. Estado imutável e formulário controlado | spread, value + onChange |
um formulário de novo agendamento que valida |
6. useEffect e dados de fora |
efeito, dependências, limpeza, carregando e erro | a agenda vinda de uma API de verdade |
| 7. Composição e contexto | children, useContext, hook customizado |
tema, usuário logado e lógica repetida em um lugar só |
| 8. Rotas | caminho, parâmetro, query string | /consultas/42 funcionando com F5 e link compartilhável |
Duas observações que economizam meses.
A primeira: as etapas 1 a 4 sustentam o restante do trabalho. Componente, JSX, props e estado reaparecem em toda funcionalidade; correr até hooks exóticos sem dominar essa base só troca entendimento por receita. Fique nas quatro primeiras até conseguir montar uma tela nova e explicar por que ela atualiza.
A segunda: só passe para a etapa 6 quando a 5 estiver automática. useEffect é
onde a trilha cobra a fatura de tudo que ficou pela metade — e é onde nascem os
loops infinitos.
Os cinco hooks que resolvem noventa por cento do trabalho
Hook é uma função que dá memória e ciclo de vida a um componente. Existem mais de dez na API; cinco pagam o aluguel.
Comece por useState. Ele guarda um valor entre
renderizações e avisa o React quando esse valor muda. Este é o componente
rodando de verdade no navegador — renderizado com react-dom/client dentro do
jsdom, com um clique disparado no botão do Thor:
import { useState } from 'react';
import { createRoot } from 'react-dom/client';
import { flushSync } from 'react-dom';
const iniciais = [
{ id: 1, pet: 'Amora', status: 'confirmada' },
{ id: 2, pet: 'Thor', status: 'aguardando' },
{ id: 3, pet: 'Nina', status: 'aguardando' },
];
function Agenda() {
const [consultas, setConsultas] = useState(iniciais);
const confirmadas = consultas.filter((c) => c.status === 'confirmada').length;
function confirmar(id) {
setConsultas((atuais) =>
atuais.map((c) => (c.id === id ? { ...c, status: 'confirmada' } : c))
);
}
return (
<section>
<p id="resumo">{confirmadas} de {consultas.length} confirmadas</p>
{consultas.map((c) => (
<button key={c.id} id={`btn-${c.id}`} onClick={() => confirmar(c.id)}>
{c.pet} — {c.status}
</button>
))}
</section>
);
}
// tela() só lê o que está na página, para eu imprimir o antes e o depois
function tela() {
return [
document.getElementById('resumo').textContent,
...[...document.querySelectorAll('button')].map((b) => b.textContent),
].join(' / ');
}
const root = createRoot(document.getElementById('root'));
flushSync(() => root.render(<Agenda />));
console.log('antes :', tela());
flushSync(() => document.getElementById('btn-2').click());
console.log('depois:', tela());Um clique, e o resumo e o botão mudaram na mesma renderização. É o exemplo do começo do guia, agora com interação real.
Os outros quatro, em ordem de quanto você vai usar:
useEffect— sincronizar o componente com algo de fora: buscar dados, assinar um evento, mexer nodocument.title. É o hook mais usado e o mais usado errado. Se o array de dependências existe para calar um aviso, o efeito está errado.useRef— guardar um valor que sobrevive ao re-render sem disparar re-render, e pegar o nó do DOM (input.current.focus()).useContext— ler um valor publicado lá em cima da árvore sem passar por todo mundo no caminho.useReducer— quando o estado tem muitas transições e osetStatevirou uma sopa deif. Um agendamento com rascunho, validando, salvo e erro é o caso clássico.
useMemo e useCallback não estão nos cinco. Eles são otimização, e
otimização sem medição é chute. Espalhá-los por hábito aumenta dependências e
torna o código mais difícil de ler sem provar ganho. Use quando o perfil do
DevTools apontar, não antes.
Onde mora cada dado: local, contexto, URL ou servidor
Esta é a decisão que mais separa código profissional de código de tutorial, e ela quase nunca é ensinada. Toda vez que um dado novo aparece na tela, você escolhe onde ele vive. Errar aqui não gera erro no console — gera um projeto que vai ficando difícil.
Em forma de tabela, com o critério explícito e o custo de errar:
| onde | use quando | ferramenta | o preço de errar |
|---|---|---|---|
| Estado local | só este componente e os filhos dele leem o dado | useState, useReducer |
subir estado que ninguém mais usa faz a tela inteira re-renderizar por um campo de busca |
| URL | o dado descreve o que está sendo visto: filtro, aba, página, id | React Router, searchParams |
F5 apaga o filtro, o usuário não consegue mandar o link e o botão voltar mente |
| Cache de servidor | o dado é uma cópia do banco, não a verdade | fetch com estado de carregando e erro, TanStack Query | você reinventa cache, revalidação e corrida de requisição, sempre pior |
| Contexto | muitos componentes distantes leem, e o dado muda pouco | Context API | contexto que muda a cada tecla re-renderiza metade do app |
A regra por trás da tabela: escolha pelo tempo de vida do dado, não pela
distância entre os componentes. Prop drilling é chato, contexto é caro — e
quase toda dor de prop drilling se resolve com composição (children) antes de
merecer um contexto.
O caso da URL é o mais subestimado, e o mais fácil de provar. Aqui o filtro da agenda não está em estado nenhum: ele é lido da query string, e o mesmo endereço sempre produz a mesma tela.
import { renderToStaticMarkup } from 'react-dom/server';
const consultas = [
{ id: 1, pet: 'Amora', status: 'confirmada', vet: 'Dra. Lima' },
{ id: 2, pet: 'Thor', status: 'aguardando', vet: 'Dr. Paz' },
{ id: 3, pet: 'Nina', status: 'confirmada', vet: 'Dr. Paz' },
{ id: 4, pet: 'Bidu', status: 'cancelada', vet: 'Dra. Lima' },
];
function Painel({ busca }) {
const params = new URLSearchParams(busca);
const status = params.get('status') ?? 'todas';
const vet = params.get('vet') ?? 'todos';
const visiveis = consultas.filter(
(c) => (status === 'todas' || c.status === status) && (vet === 'todos' || c.vet === vet)
);
return (
<ul>
{visiveis.map((c) => (
<li key={c.id}>{`${c.pet} (${c.vet})`}</li>
))}
</ul>
);
}
for (const busca of ['', '?status=confirmada', '?status=confirmada&vet=Dr.%20Paz']) {
console.log(busca || '(sem filtro)');
console.log(renderToStaticMarkup(<Painel busca={busca} />));
}Três URLs, três telas, zero useState. A recepcionista da clínica manda o link
para a veterinária e a tela chega igual do outro lado. Com o filtro em estado
local isso é impossível — e o botão voltar do navegador passa a ignorar a
última coisa que a pessoa fez.
Vite, Next.js ou React puro: quando cada um
React sozinho é um pacote no npm. Alguém precisa transformar JSX em JavaScript, servir os arquivos e recarregar a tela enquanto você digita. Hoje existem três respostas razoáveis, e a escolha é mais simples do que a internet faz parecer.
Vite, para aprender e para aplicação atrás de login. É a escolha desta trilha porque mantém a montagem pequena e deixa os conceitos do React visíveis. Uma agenda de clínica que só abre depois do login normalmente não precisa de renderização no servidor para entregar a primeira versão.
Para dar um número em vez de adjetivo: este é o build de produção da agenda
inteira — React 19.2.8, um componente com estado e evento, StrictMode ligado —
com Vite 8.2.2 num MacBook. Rodei três vezes seguidas: o tamanho saiu igual nas
três, e o tempo variou entre 48 e 51 ms. Abaixo, o terminal de uma delas:
npx vite build✓ built in 48ms
Guarde os 60 kB comprimidos: eles voltam mais adiante, quando a pergunta for quando não usar React.
Next.js, quando a página precisa ser encontrada no Google. Site institucional, blog, catálogo, loja. Ele resolve renderização no servidor, rotas por arquivo e metadados — e cobra em conceitos novos: cliente e servidor, cache, streaming. É excelente, e é a segunda coisa a aprender, não a primeira.
React puro num <script>, quase nunca. Existe, funciona para colar um
componente numa página legada, e não é onde você deve começar.
Os erros que denunciam que você entendeu errado
Três bugs. Nenhum deles é de sintaxe, e cada um revela um modelo mental furado.
1. Mutar o estado: o dado muda e a tela não
Este é o campeão. A única diferença para o exemplo do useState lá em cima é
que aqui o confirmar altera o objeto no lugar e devolve o mesmo array:
// tudo o mais é igual ao exemplo anterior; só o confirmar mudou
function confirmar(id) {
setConsultas((atuais) => {
atuais.find((c) => c.id === id).status = 'confirmada';
return atuais;
});
}
// e, depois do clique, imprimo também o array que foi para o useState
console.log('dado :', iniciais.map((c) => `${c.pet}=${c.status}`).join(' / '));Leia as três linhas com calma. A tela é idêntica antes e depois. O dado, na terceira linha, mudou: o Thor está confirmado no array. O React comparou a referência antiga com a nova, viu o mesmo array e concluiu, corretamente, que não havia nada para redesenhar.
Não existe mensagem de erro para isso — é o pior tipo de bug. A correção é
sempre criar um valor novo, com map e spread, atualizando o estado sem mutar o
valor anterior.
2. Hook dentro de if: o estado do vizinho
Hook não é chamado por nome; é chamado por posição. O React guarda os
valores numa lista e conta a ordem das chamadas. Um if em volta quebra a
contagem:
import { useState } from 'react';
import { createRoot } from 'react-dom/client';
import { flushSync } from 'react-dom';
function FiltroDaAgenda({ mostrarBusca }) {
if (mostrarBusca) {
const [termo] = useState('');
return <input defaultValue={termo} />;
}
const [status] = useState('todas');
return <span>{status}</span>;
}
// o mesmo componente, no mesmo lugar da árvore, com a prop trocada
const root = createRoot(document.getElementById('root'));
flushSync(() => root.render(<FiltroDaAgenda mostrarBusca={false} />));
console.log('render 1:', document.getElementById('root').innerHTML);
flushSync(() => root.render(<FiltroDaAgenda mostrarBusca={true} />));
console.log('render 2:', document.getElementById('root').innerHTML);O useState('') devolveu 'todas'. O campo de busca nasceu preenchido com o
estado do filtro anterior, porque os dois ocupam a primeira posição da lista de
hooks do componente. Sem erro, sem aviso.
Acrescente um segundo useState dentro do if — uma paginação, por exemplo — e
aí sim o React percebe a contagem trocada e reclama alto:
Previous render Next render
- useState useState
- undefined useState ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: Rendered more hooks than during the previous render.
Por isso a regra: todo hook no topo do componente, sempre, sem condição e sem
laço. O if vai depois, no que a função devolve.
3. Lista sem key
import { renderToStaticMarkup } from 'react-dom/server';
const consultas = [
{ id: 1, pet: 'Amora', status: 'confirmada' },
{ id: 2, pet: 'Thor', status: 'aguardando' },
];
function Lista() {
return (
<ul>
{consultas.map((c) => (
<li>{c.pet}</li>
))}
</ul>
);
}
renderToStaticMarkup(<Lista />); // basta renderizar uma vez para o aviso sairCheck the render method of Lista. See https://react.dev/link/warning-keys for more information.
A página funciona, o aviso some no meio do console, e o bug aparece três semanas
depois: você remove a consulta do meio e o campo de texto de uma linha
“pula” para outra. A key é como o React identifica cada item entre duas
renderizações. Use o id do banco. Nunca use o índice do map numa lista que
reordena, filtra ou remove.
O que mudou no React 19 e o que virou lenda
Muito material em português ainda descreve um React de 2021. Três correções.
ref agora é uma prop comum. forwardRef não é mais necessário em
componente de função. Este código roda em React 19.2.8, com o foco indo para o
input que está dentro de outro componente:
import { useRef, version } from 'react';
import { createRoot } from 'react-dom/client';
import { flushSync } from 'react-dom';
function CampoBusca({ ref, ...props }) {
return <input ref={ref} placeholder="Buscar pet..." {...props} />;
}
function Painel() {
const campo = useRef(null);
return (
<>
<CampoBusca ref={campo} />
<button id="focar" onClick={() => campo.current.focus()}>Buscar</button>
</>
);
}
const root = createRoot(document.getElementById('root'));
flushSync(() => root.render(<Painel />));
flushSync(() => document.getElementById('focar').click());
console.log('React', version);
console.log('elemento com foco:', document.activeElement.outerHTML);O React Compiler existe e é opcional. Ele memoriza por você em tempo de
compilação, o que reduz a necessidade de useMemo e useCallback escritos à
mão. É um plugin que você liga; não é mágica que já está ligada no seu projeto.
React Server Components rodam no
servidor e não têm estado. Eles chegam via framework — Next.js,
principalmente —, não via npm install react. Num projeto Vite você simplesmente
não tem esse assunto, e não está perdendo nada aos três meses de estudo.
E as lendas que continuam circulando: componente de classe não é o padrão
(hooks são desde 2019); Redux não é obrigatório; create-react-app não
deve ser usado; e o Virtual DOM não é “mais rápido que o DOM” — ele é uma
forma de descobrir o mínimo a mudar, o que quase sempre sai mais barato do que
redesenhar tudo, e mais caro do que uma atualização manual perfeita que ninguém
consegue manter.
Três projetos que valem mais do que dez tutoriais
Um projeto terminado ensina mais que cinco começados. Estes três, nesta ordem, cobrem tudo que aparece numa entrevista júnior — e todos cabem na mesma clínica veterinária.
1. A agenda com filtro na URL. Lista de consultas, filtro por status e por veterinário, contador de confirmadas. Sem back-end: um array em arquivo já serve. O critério de pronto é o link: copie o endereço com o filtro aplicado, abra numa aba anônima e a tela precisa ser a mesma.
2. O cadastro de pacientes consumindo API. Um formulário controlado que cria, uma lista que busca de uma API real e três estados desenhados na tela: carregando, erro e vazio. O estado vazio é o que separa portfólio de exercício — quase ninguém desenha, e todo revisor repara.
3. O painel com rotas e sessão. Rotas para /consultas, /consultas/:id e
/pacientes, um contexto com o usuário logado e um hook customizado que você
extraiu porque dois componentes repetiam a mesma lógica. Aqui você exercita, de
uma vez, tudo o que a tabela de decisão do meio deste guia descreve.
Para construir essa terceira entrega com dados, filtros, formulário, persistência e testes, siga o tutorial Painel React com TypeScript e Vite. Ele transforma o roteiro acima num projeto incremental que você pode verificar.
Publique os três. Um projeto que roda numa URL vale mais que dez repositórios com README bonito.
Para mostrar que não é conversa, este é o cartão de consulta testado com
node:test, sem nenhuma biblioteca de teste instalada. O Node não lê .jsx
sozinho — o arquivo passou antes pelo esbuild, o mesmo transformador de JSX que
o seu projeto Vite já tem — e aí node --test roda:
import test from 'node:test';
import assert from 'node:assert/strict';
import { renderToStaticMarkup } from 'react-dom/server';
function CardConsulta({ pet, tutor, horario, status }) {
return (
<article className={`consulta consulta--${status}`}>
<h3>{pet}</h3>
<p>Tutor: {tutor}</p>
<p>Horário: {horario}</p>
</article>
);
}
const props = { pet: 'Amora', tutor: 'Ana Souza', horario: '09:00', status: 'confirmada' };
test('mesmas props, mesma tela', () => {
assert.equal(
renderToStaticMarkup(<CardConsulta {...props} />),
renderToStaticMarkup(<CardConsulta {...props} />)
);
});
test('o status vira classe no HTML', () => {
const html = renderToStaticMarkup(<CardConsulta {...props} status="cancelada" />);
assert.match(html, /consulta--cancelada/);
});
test('o nome do pet aparece no título', () => {
const html = renderToStaticMarkup(<CardConsulta {...props} pet="Thor" />);
assert.match(html, /<h3>Thor<\/h3>/);
});Quando não usar React
A pergunta que quase nenhum guia faz, e que decide bem mais projeto do que a escolha entre hooks.
Lembra dos 60,12 kB comprimidos do build mínimo? Esse é o piso que o visitante baixa antes de ver o primeiro pixel — para uma página que, em HTML e CSS puros, pesaria menos de 5 kB. Numa aplicação de trabalho isso se paga em minutos. Numa landing page, não se paga nunca.
Não use React quando:
- A página é conteúdo e o Google precisa achar. Site institucional da clínica, blog, página de contato. HTML, CSS e um pouco de JavaScript entregam mais rápido, indexam melhor e não quebram quando o script falha.
- A interatividade cabe em cinquenta linhas. Um menu que abre, um formulário
com três campos, um contador.
addEventListenerresolve, e você não instala nada. - O projeto é legado e você quer “modernizar aos poucos”. Meia migração é a pior das arquiteturas: dois modelos mentais no mesmo repositório, e ninguém sabe qual manda.
- Você ainda não escreve JavaScript sozinho. É o caso mais frequente, e o mais caro. Sem a base, React vira um conjunto de rituais que você repete sem entender — e o primeiro erro fora do caminho feliz trava tudo.
Use React quando a tela tem muitos estados que conversam entre si e a mesma informação aparece em mais de um lugar. Foi exatamente o caso do resumo e da lista lá no começo. Quando esse problema não existe, React é custo sem contrapartida.
Por onde começar hoje
Se a base de JavaScript está firme, comece por
o que é React e siga a
trilha de React na ordem: componente, props, listas,
useState. São quatro lições, cada uma com código executado e o erro mais comum
reproduzido — os mesmos três que você viu aqui aparecem no lugar em que
costumam pegar as pessoas.
E abra o projeto da agenda hoje mesmo, ainda que com um array inventado. React não se aprende lendo sobre React: aprende-se com uma tela na frente que precisa mudar quando o dado muda.
Trilha
React
Componentes, estado e as decisões que aparecem quando a tela começa a crescer.
- 01O que é React: componentes, estado e para que serve
- 02Criar projeto React com Vite: passo a passo
- 03JSX no React: escrever HTML dentro do JavaScript
- 04Props no React: passar dados de um componente para outro
- 05Renderização condicional no React: if, && e ternário
- 06Renderizar listas no React com map e a prop key
- 07Eventos no React: onClick, onChange e o objeto do evento
- 08useState no React: guardar e atualizar o estado da tela
- 09Atualizar estado no React sem mutar array e objeto
- 10Formulário controlado no React: value e onChange
- 11useEffect no React: efeito, dependências e limpeza
- 12Consumir API no React: fetch, carregando e erro
- 13useRef no React: acessar o DOM e guardar valor
- 14useMemo e useCallback: quando memorizar de verdade
- 15Hook customizado no React: extrair lógica repetida
- 16Context API no React: estado sem ficar passando props
- 17useReducer no React: estado com muitas transições
- 18children e composição no React: o fim do prop drilling
- 19React Router: rotas, links e parâmetros na URL
- 20CSS no React: módulos, Tailwind ou styled-components
react
Painel React com TypeScript e Vite: projeto completo
Rendered more hooks than during the previous render
Maximum update depth exceeded: o loop de re-render
Each child in a list should have a unique key prop
React Server Components: o que roda no servidor
Re-render no React: por que o componente roda de novo
Perguntas frequentes
Preciso saber TypeScript antes de aprender React?
React, Vue ou Angular: por qual começar?
Como saber se já consigo construir um projeto React sozinho?
Preciso aprender Redux?
Ainda preciso reconhecer componente de classe?
Dá para aprender React sem saber HTML e CSS direito?
O código deste guia foi executado em Node 24.16.0, React 19.2.8, jsdom 30.0.1, Vite 8.2.2, e as saídas exibidas são as reais — como produzimos este conteúdo.
Fontes consultadas
- React — Learn React — react.dev
- React — Rules of Hooks — react.dev
- React 19 — release oficial — react.dev
- React — Sunsetting Create React App — react.dev
- Vite — Getting Started — vite.dev





