React do básico ao super avançado
Um guia para aprender React de verdade: não só a sintaxe, mas o modelo mental, os trade-offs, a arquitetura moderna, o futuro do ecossistema e um caminho concreto de estudo no macOS.
Muita gente tenta aprender React como se fosse uma lista de comandos: useState, useEffect, props, componentes e pronto. Isso quase sempre gera conhecimento frágil. React fica muito mais claro quando você entende o problema que ele resolve: organizar interfaces complexas como funções previsíveis de estado ao longo do tempo.
O que é React — e o que ele não é
React é uma biblioteca JavaScript para construir interfaces de usuário. Ele nasceu no Facebook com uma ideia forte: em vez de manipular o DOM manualmente, você descreve como a interface deve parecer para um certo estado, e o React cuida de atualizar a tela.
Isso parece pequeno, mas muda quase tudo. A UI deixa de ser uma sequência de mutações imperativas e passa a ser uma projeção declarativa de dados.
- Não é linguagem. A linguagem é JavaScript — ou TypeScript por cima dele.
- Não é framework full stack por si só. Ele cuida da camada de interface.
- Não resolve tudo sozinho. Roteamento, cache, build, forms, testes e dados dependem do ecossistema.
Por que React ficou tão relevante
React ganhou força porque ofereceu uma forma melhor de lidar com interfaces ricas. Antes dele, aplicações front-end grandes sofriam com três dores recorrentes: manipulação manual demais, acoplamento espalhado e dificuldade de raciocinar sobre mudanças.
O React atacou isso com alguns princípios simples:
- Componentização: dividir UI em peças pequenas e reutilizáveis.
- One-way data flow: dados descem de forma previsível.
- Renderização declarativa: você descreve o resultado, não os passos do DOM.
- Composição: componentes são combinados como blocos.
O motivo real do sucesso, porém, não foi só técnico. Foi também organizacional: React favorece times grandes porque incentiva fronteiras mais nítidas entre partes da interface.
O que aprender antes de mergulhar
React parece mais difícil quando o problema está antes dele. Muitos travam não por causa de React em si, mas porque ainda não dominam JavaScript moderno, módulos, arrays, objetos, funções, closures e assincronismo.
Antes de tentar aprender tópicos avançados, vale ter segurança em:
- JavaScript moderno:
let,const, arrow functions, destructuring, spread, rest, módulos ES. - Assincronismo:
Promise,async/await,fetch. - HTML e CSS: sem isso, a camada visual vira caixa-preta.
- Ferramentas de terminal: instalar Node, rodar scripts, entender dependências.
Ambiente recomendado no macOS
Como você usa macOS, vale montar um ambiente limpo e estável desde cedo. A melhor forma de evitar confusão com versões de Node é usar um gerenciador de versões em vez de depender de instalações soltas.
# instalar Homebrew se ainda não existir
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# instalar nvm ou fnm; fnm costuma ser mais rápido
brew install fnm
eval "$(fnm env --use-on-cd)"
fnm install --lts
fnm use lts-latest
# ferramentas úteis
brew install git
brew install jq
brew install watchman
Minha recomendação para editor é VS Code ou Zed. Para navegador de desenvolvimento, use Chrome ou Arc com DevTools fortes. E instale a extensão React Developer Tools.
- Node LTS para estabilidade.
- fnm ou nvm para trocar de versão sem dor.
- watchman pode ajudar em file watching em projetos maiores.
- iTerm2 ou Terminal padrão do macOS, com zsh bem configurado.
O modelo mental que muda tudo
O coração de React é este: UI = f(state). A interface é uma função do estado atual.
Quando o estado muda, a interface é recalculada. Você não diz “mude aquele botão, esconda aquela div, pinte aquele texto”; você diz “quando o estado for X, a interface deve parecer Y”.
Primeiro exemplo: um componente simples
O exemplo mais básico de React é um componente funcional. Um componente é uma função que recebe dados e retorna uma descrição de UI.
function Saudacao({ nome }) {
return <h1>Olá, {nome}!</h1>;
}
export default function App() {
return <Saudacao nome="Marinho" />;
}
Aqui já existem ideias fundamentais:
- props: os dados de entrada.
- composição:
AppusaSaudacao. - declaratividade: a UI é retornada diretamente.
JSX: por que misturar “HTML” com JavaScript
JSX causa estranheza no começo porque parece HTML dentro de JavaScript. Mas a motivação é coerente: estrutura visual e lógica de renderização quase sempre pertencem ao mesmo componente.
A alternativa antiga era separar por tecnologia, não por responsabilidade. Isso parecia organizado, mas espalhava a mesma feature por vários arquivos desconectados.
JSX não é HTML real; é uma sintaxe transformada em chamadas JavaScript. Em essência, você está escrevendo árvores de elementos.
Props, state e a fronteira entre dados externos e internos
Uma forma muito útil de pensar:
- props são dados que vêm de fora.
- state são dados que o componente controla por dentro.
import { useState } from 'react';
function Contador() {
const [count, setCount] = useState(0);
return (
<div>
<p>Valor atual: {count}</p>
<button onClick={() => setCount(count + 1)}>
Incrementar
</button>
</div>
);
}
O aprendizado importante aqui não é memorizar useState. É perceber que o clique muda o estado,
e a mudança de estado dispara uma nova renderização. React não “atualiza o texto” diretamente; ele recalcula a UI.
Listas, chaves e renderização condicional
Interfaces reais quase sempre envolvem listas e condições. Em React, isso acontece com JavaScript normal.
const tarefas = [
{ id: 1, titulo: 'Estudar JSX' },
{ id: 2, titulo: 'Entender hooks' },
{ id: 3, titulo: 'Praticar componentes' }
];
function ListaDeTarefas() {
return (
<ul>
{tarefas.map((tarefa) => (
<li key={tarefa.id}>{tarefa.titulo}</li>
))}
</ul>
);
}
A key existe para ajudar o React a reconciliar itens de forma correta entre renderizações.
Muita gente trata isso como “warning chato”, mas é parte da identidade dos elementos da lista.
Hooks: a API que exige mais disciplina mental
Hooks foram criados para reutilizar lógica com mais clareza do que HOCs e render props. Eles deixaram o código mais expressivo, mas também trouxeram armadilhas para quem tenta usá-los sem entender execução de função, closures e ciclo de renderização.
Os hooks mais importantes no começo são:
useStatepara estado local.useEffectpara sincronizar com sistemas externos.useMemopara memoização de cálculos.useCallbackpara estabilidade de funções quando isso importa.useRefpara valores mutáveis persistentes e acesso a elementos.
useEffect não é “lugar para qualquer código depois do render”. Ele existe para sincronizar o componente com algo externo:
rede, DOM imperativo, timer, subscription, storage, analytics, WebSocket e assim por diante.
O erro clássico com useEffect
O hook mais mal compreendido do React costuma ser useEffect. O problema não é a API em si; é a motivação errada.
Quando a pessoa pensa “preciso rodar algo depois”, começa a entupir efeitos com lógica que deveria estar no render, em eventos ou em derivação de estado.
useEffect(() => {
setNomeCompleto(nome + ' ' + sobrenome);
}, [nome, sobrenome]);
Aqui o valor é derivável. Você não precisa de estado extra nem de efeito. Basta calcular:
const nomeCompleto = `${nome} ${sobrenome}`;
Esse tipo de distinção separa código React idiomático de código React que “funciona, mas luta contra a biblioteca”.
Componentes puros, re-render e previsibilidade
React recompensa componentes puros: dado o mesmo input, eles devem produzir a mesma saída visual. Essa previsibilidade melhora testes, depuração e performance.
Quando você enfia efeitos colaterais no corpo do componente, mistura leitura e escrita de estado sem clareza, ou depende de mutações invisíveis, o raciocínio se deteriora.
Busca de dados: da abordagem simples ao ecossistema moderno
Em projetos pequenos, você pode usar fetch dentro de um efeito. Em projetos reais, isso escala mal rápido.
Cache, revalidação, loading, retry, erro, cancelamento e sincronização entre telas logo aparecem.
Por isso bibliotecas como TanStack Query se tornaram tão importantes. Elas tiram do componente a responsabilidade de gerenciar o ciclo de vida do dado remoto.
import { useEffect, useState } from 'react';
function Usuarios() {
const [usuarios, setUsuarios] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function carregar() {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const data = await response.json();
setUsuarios(data);
setLoading(false);
}
carregar();
}, []);
if (loading) return <p>Carregando...</p>;
return (
<ul>
{usuarios.map((usuario) => (
<li key={usuario.id}>{usuario.name}</li>
))}
</ul>
);
}
Esse exemplo ensina o básico. Mas em produção você quase sempre vai querer uma camada mais robusta.
Roteamento, formulários e estado compartilhado
Depois dos fundamentos, React “puro” logo encontra três temas maiores: navegação, formulários e compartilhamento de estado.
- Roteamento: React Router ou o sistema de rotas do Next.js.
- Formulários: React Hook Form costuma ser uma escolha excelente.
- Estado global: Context, Zustand, Redux Toolkit, Jotai e outros, dependendo do caso.
O erro comum é promover qualquer estado para o nível global cedo demais. Estado global deve ser usado quando o dado realmente precisa ser compartilhado, persistido ou coordenado entre áreas diferentes da aplicação.
TypeScript: quando e por que entrar
Para projetos pequenos, JavaScript puro é suficiente para aprender React. Mas à medida que a base cresce, TypeScript se torna quase inevitável para manutenibilidade séria.
O ganho não é só “tipar por tipar”. O ganho é estrutural:
- documenta contratos de props;
- reduz classes inteiras de bugs;
- melhora autocomplete e refatoração;
- deixa componentes e APIs internas mais explícitos.
type BotaoProps = {
label: string;
onClick: () => void;
disabled?: boolean;
};
function Botao({ label, onClick, disabled = false }: BotaoProps) {
return (
<button onClick={onClick} disabled={disabled}>
{label}
</button>
);
}
Comparações importantes: React vs outras abordagens
Aprender React fica mais fácil quando você o compara com alternativas. Isso força você a enxergar não só “como fazer”, mas por que o design dele é desse jeito.
| Tecnologia | Força principal | Trade-off principal |
|---|---|---|
| React | Ecossistema enorme, composição forte, mercado amplo | Muitas decisões ficam para o ecossistema |
| Vue | Curva mais suave e estrutura amigável | Mercado e ecossistema variam por região |
| Angular | Framework completo e opinativo | Peso conceitual maior no começo |
| Svelte | Sintaxe enxuta e sensação de simplicidade | Ecossistema menor e menos demanda de mercado |
| Solid | Reatividade fina e boa performance | Menor adoção, menos material e menos vagas |
Uma comparação útil é esta: React privilegia composição e flexibilidade; frameworks mais opinativos privilegiam convenção e trilha mais guiada. Nenhuma escolha é universalmente superior. A pergunta correta é: qual modelo serve melhor ao time, ao produto e ao ecossistema que você quer habitar?
Arquitetura de projetos React
No nível intermediário para avançado, a dificuldade deixa de ser sintaxe e passa a ser arquitetura. A aplicação cresce; o código deixa de caber na cabeça; decisões de pasta, boundaries e ownership passam a importar.
Uma arquitetura saudável costuma separar pelo menos:
- UI components: componentes visuais reutilizáveis.
- feature components: componentes ligados a uma parte do produto.
- hooks: lógica reutilizável de UI e dados.
- services: acesso a APIs e integrações.
- state: contratos de dados locais e globais.
O ponto central: organize por responsabilidade, não por obsessão estética com árvore de diretórios.
Performance: o que realmente importa
Muita gente aprende performance em React pela ordem errada. Começa decorando memo, useMemo e useCallback
antes de entender onde o tempo está sendo gasto.
Em geral, a ordem correta é:
- ter uma UI correta e simples;
- medir com React DevTools Profiler;
- identificar gargalos reais;
- só então aplicar memoização seletiva.
A pior performance optimization é a que complica o código inteiro sem resolver gargalo de verdade.
useMemo e useCallback não são medalhas de senioridade. São ferramentas pontuais.
Use quando houver motivo concreto: evitar recomputação cara, estabilizar referência em integração específica ou reduzir renders custosos comprovados.
React moderno: concurrent rendering, suspense e server components
O React contemporâneo já não é só “biblioteca para SPA”. O projeto avançou em direção a um modelo mais amplo de renderização, streaming e integração entre cliente e servidor.
Alguns termos importantes:
- Concurrent rendering: o React pode priorizar melhor trabalho de renderização.
- Suspense: coordenação declarativa de estados de espera.
- Server Components: parte da árvore pode ser renderizada no servidor e enviada já pronta.
- Streaming: a página não precisa esperar tudo para começar a responder.
Isso aproxima React de uma visão mais sofisticada de full stack UI. O futuro do ecossistema está fortemente ligado a essa direção.
Por que Next.js aparece tanto quando se fala de React
React sozinho te ensina bem a camada de componentes. Mas aplicações reais geralmente precisam de roteamento, renderização híbrida, deploy, data fetching no servidor, assets, SEO e estrutura de aplicação. É aí que Next.js entra.
Você pode pensar assim:
- React ensina a pensar a interface.
- Next.js ensina a colocar essa interface num produto web moderno.
Por isso minha recomendação de trajetória é: primeiro Vite para aprender fundamentos, depois Next.js para entender o stack de mercado.
Testes em React
Testar React bem não é testar implementação interna; é testar comportamento percebido pelo usuário. Bibliotecas como Testing Library ajudam justamente nisso.
O ideal é cobrir três níveis:
- unitário: lógica isolada, hooks e funções utilitárias;
- integração: componentes conversando entre si;
- end-to-end: fluxo real no navegador com Playwright ou Cypress.
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Contador from './Contador';
test('incrementa o contador ao clicar', async () => {
render(<Contador />);
const botao = screen.getByRole('button', { name: /incrementar/i });
await userEvent.click(botao);
expect(screen.getByText(/valor atual: 1/i)).toBeInTheDocument();
});
Erros comuns de quem está aprendendo
- aprender React antes de JavaScript;
- usar
useEffectpara tudo; - subir estado demais cedo demais;
- globalizar qualquer dado local;
- criar abstrações cedo demais;
- otimizar performance sem medir;
- decorar API sem entender o fluxo de renderização.
Roteiro de aprendizado do básico ao super avançado
Se eu montasse uma trilha progressiva, faria assim:
- Base web: HTML, CSS, DOM, JavaScript moderno.
- Fundamentos React: JSX, componentes, props, state, eventos, listas, condições.
- Hooks: useState, useEffect, useRef, useMemo, useCallback, hooks customizados.
- Dados: fetch, loading, erro, cache, TanStack Query.
- Aplicação real: roteamento, formulários, autenticação, design system.
- TypeScript: tipos de props, unions, generics, typing de hooks.
- Performance: profiling, memoização seletiva, virtualização.
- Arquitetura: boundaries, pastas, estado compartilhado, testes.
- React moderno: Suspense, streaming, Server Components, Next.js.
- Nível sênior: trade-offs, observabilidade, DX, design de APIs internas e revisão de arquitetura.
Projetos recomendados para fixar
React só entra de verdade quando você constrói. Minha sugestão é evoluir por projetos com dificuldade crescente.
- Contador + lista de tarefas para estado local e eventos.
- Buscador de usuários para fetch, loading e erro.
- Dashboard simples para composição, filtros e tabelas.
- CRUD completo para formulários, validação e cache.
- App com autenticação para arquitetura real.
- Mini e-commerce para carrinho, rotas, estado global e performance.
Quiz para testar entendimento
Use este quiz como diagnóstico. O ideal é responder sem olhar para cima e só depois comparar com o gabarito.
- Qual a diferença conceitual entre props e state?
- Por que React é descrito como declarativo?
- Quando
useEffectfaz sentido e quando ele é exagero? - Por que
keyé importante em listas? - Em que cenário
useMemopode valer a pena? - Qual a vantagem de usar TypeScript em projetos React maiores?
- Qual a diferença prática entre React e Next.js?
- Por que medir vem antes de otimizar performance?
- O que significa pensar em UI como função do estado?
- Por que aprender JavaScript bem acelera o aprendizado de React?
Gabarito resumido
- Props vêm de fora; state é controlado pelo componente.
- Porque você descreve o resultado visual desejado para um estado, em vez de manipular o DOM passo a passo.
- Faz sentido para sincronizar com sistemas externos; é exagero quando serve só para derivar valores internos.
- Porque ajuda o React a identificar corretamente cada item entre renderizações.
- Quando há cálculo caro ou necessidade real de estabilizar referência em gargalo comprovado.
- Contratos mais claros, menos bugs, melhor refatoração e autocomplete.
- React é a biblioteca de UI; Next.js organiza a aplicação web moderna ao redor dela.
- Porque otimização sem profiling costuma aumentar complexidade sem atacar gargalo real.
- Que a tela é consequência dos dados atuais.
- Porque React usa intensamente conceitos da própria linguagem: funções, arrays, closures, módulos e async.
O futuro do React
O futuro do React parece menos ligado a “mais componentes no cliente” e mais ligado a coordenação inteligente entre cliente e servidor. Isso inclui streaming, renderização parcial, boundary mais clara entre dados e interatividade e melhor ergonomia para apps grandes.
Em outras palavras: React está se movendo de uma biblioteca de UI para um modelo de aplicação cada vez mais abrangente, especialmente quando combinado com frameworks como Next.js.
Isso não significa que SPAs tradicionais morreram. Significa que o espaço de soluções ficou maior e mais sofisticado.
O que eu recomendaria para você
Considerando que você usa macOS e quer aprender com profundidade, eu seguiria esta estratégia:
- instalar Node LTS com fnm;
- começar com Vite + React por 2 ou 3 projetos pequenos;
- estudar JavaScript moderno em paralelo;
- entrar em TypeScript cedo, mas não no primeiro dia;
- migrar para Next.js quando os fundamentos estiverem sólidos;
- usar React DevTools desde cedo;
- aprender a explicar em voz alta por que um componente renderiza.
Se você consegue explicar quem possui o estado, quem recebe props, quando há efeito externo e por que aquela árvore re-renderiza, seu entendimento já começou a ficar realmente forte.