Em uma frase
O React é uma biblioteca JavaScript para construir interfaces de usuário, quebrando-as em pedaços de código autocontidos e reutilizáveis chamados "componentes", que se atualizam automaticamente quando seus dados mudam.
O problema que ele resolve
Imagine o desenvolvimento web nos velhos tempos (tipo, no começo dos anos 2010). Você tinha uma página web e queria torná-la interativa. Talvez quisesse que um botão de "curtir" ficasse azul e atualizasse um contador ao ser clicado. Usando uma ferramenta como o jQuery, você escreveria um código que dizia: "encontre o botão na página, escute por um clique e, quando acontecer, encontre o elemento do contador e mude seu texto, depois encontre o ícone do botão e mude sua cor."
Essa é uma abordagem imperativa. Você está dando ao navegador uma receita passo a passo de como mudar a página. Funciona para um botão de curtir. Mas e para um feed de rede social completo, com centenas de posts, comentários, notificações e uma janela de chat ao vivo, tudo atualizando ao mesmo tempo? As "receitas" se tornam um emaranhado de código espaguete. Uma mudança em um lugar poderia, de forma imprevisível, quebrar outra coisa completamente diferente. Manter a UI consistente com os dados da aplicação era uma batalha constante e suscetível a erros.
O Facebook estava vivendo esse pesadelo em escala. Em 2011, eles criaram o React para resolver esse problema internamente. O React introduziu um modelo declarativo. Em vez de dizer ao navegador como mudar as coisas, você apenas descreve como a UI deveria se parecer para um determinado estado. Você declara: "Se o post estiver curtido, o botão deve ser azul e a contagem deve ser 101. Se não estiver curtido, o botão é cinza e a contagem é 100." E é isso. Quando o estado curtido muda de false para true, o React se encarrega de descobrir a maneira mais eficiente de atualizar o botão e o contador. Ele cuida do "como", para que você possa focar no "o quê".
Essa mudança do pensamento imperativo para o declarativo foi uma revolução. Ela tornou a construção de UIs complexas e orientadas a dados mais previsível, escalável e fácil de debugar.
Como funciona por debaixo dos panos
A "mágica" do React não é mágica de verdade; é uma combinação inteligente de três ideias centrais: JSX, Componentes com Estado (State), e o DOM Virtual.
JSX: JavaScript com Açúcar Sintático
Quando você olha para o código React, vê algo que se parece muito com HTML embutido diretamente no JavaScript. Isso é JSX (JavaScript XML).
const greeting = <h1>Olá, usuário do FlowingDev!</h1>;
Seu navegador não tem ideia do que fazer com isso. Não é JavaScript válido. Antes que esse código possa rodar, ele precisa ser "transpilado" (transformado) por uma ferramenta como o Babel. A linha de JSX acima é convertida em uma chamada de função JavaScript comum.
const greeting = React.createElement("h1", null, "Olá, usuário do FlowingDev!");
Cada tag JSX se torna uma chamada a React.createElement(). Essa chamada de função não cria um elemento HTML de verdade. Ela cria um objeto JavaScript leve que descreve o elemento que você quer criar — seu tipo (h1), suas propriedades (nenhuma, neste caso, então null), e seus filhos ("Olá..."). Esses objetos são os blocos de construção do DOM Virtual.
Então, JSX é apenas "açúcar sintático". Ele nos permite descrever nossa UI com uma sintaxe familiar, parecida com a do HTML, mas por debaixo dos panos, estamos apenas criando uma árvore de objetos JavaScript.
Componentes e Estado: O Cérebro da Operação
Um componente é uma função JavaScript que retorna um pouco de JSX. É um pedaço de UI reutilizável e autocontido.
function Greeting({ name }) {
return <h1>Olá, {name}!</h1>;
}
Este componente Greeting é simples. Ele recebe um name como entrada (chamado de "prop") e renderiza um título. Mas e se quisermos que um componente se lembre das coisas e mude com o tempo, como um contador? Para isso, precisamos de "estado" (state).
O estado (state) são os dados que um componente "possui" e pode alterar. O React fornece funções especiais chamadas "hooks" para gerenciar isso. A mais comum é a useState.
import { useState } from 'react';
function Counter() {
// "count" é nossa variável de estado.
// "setCount" é a *única* função que podemos usar para atualizá-la.
const [count, setCount] = useState(0); // O valor inicial é 0.
return (
<div>
<p>Você clicou {count} vezes</p>
<button onClick={() => setCount(count + 1)}>
Clique aqui
</button>
</div>
);
}
Quando você chama setCount(count + 1), não está apenas mudando uma variável. Você está dizendo ao React: "Ei, o estado deste componente Counter mudou. Por favor, rode essa função de novo para pegar a nova UI e depois atualize a tela." O React então "re-renderiza" o componente, obtém o novo JSX com o count atualizado e atualiza a página da web de forma eficiente.
O DOM Virtual: A Arma Secreta do React
Alterar diretamente o DOM real do navegador (a árvore viva de elementos HTML) é lento. É como redecorar um cômodo derrubando todas as paredes e reconstruindo-as, mesmo que você só quisesse mover um porta-retrato.
O React evita esse trabalho custoso com sua arma secreta: o DOM Virtual (VDOM). O VDOM é apenas uma cópia do DOM mantida na memória do JavaScript. É aquela árvore de objetos React.createElement da qual falamos.
Este é o processo, conhecido como reconciliação (reconciliation):
- Renderização Inicial: Quando o
Counterrenderiza pela primeira vez, o React constrói uma árvore VDOM que descreve umadivcontendo umpcom o texto "Você clicou 0 vezes" e umbutton. Ele então usa isso para criar os elementos do DOM real na página. - Mudança de Estado: Você clica no botão.
setCount(1)é chamado. - Re-renderização e Novo VDOM: O React executa novamente a função
Counter. Ele constrói uma nova árvore VDOM. Essa nova árvore é quase idêntica à antiga, mas opagora descreve o texto "Você clicou 1 vezes". - Diffing: O algoritmo de "diffing" (comparação) do React compara a nova árvore VDOM com a antiga. Ele passa rapidamente por elas e encontra as diferenças. Neste caso, ele encontra apenas uma diferença: o texto dentro da tag
<p>mudou. - Atualização em Lote (Batch): O React pega essa única pequena mudança e a aplica ao DOM real. Ele não mexe na
divou nobutton; ele apenas atualiza o texto dop.
Esse processo de "diff-and-patch" (comparar e aplicar) é incrivelmente rápido. Ao agrupar as atualizações em lote e minimizar a manipulação direta do DOM real, que é lento, o React faz com que as UIs pareçam ágeis e responsivas, mesmo quando dados complexos estão mudando rapidamente.
Casos do mundo real
O Caso dos Dados de Formulário que Desapareciam
Um dev júnior recebeu a tarefa de construir um formulário complexo de cadastro de usuário com várias etapas. Cada etapa era um componente diferente. Em um certo momento, ele precisou de um pequeno checkbox na Etapa 2 para mostrar condicionalmente um campo de entrada extra. Ele implementou, mas de repente, se deparou com um bug bizarro: sempre que um usuário marcava essa caixa, todos os dados que ele havia inserido na Etapa 2 desapareciam.
O culpado era um mal-entendido sobre as "keys". Para mostrar o campo extra, o desenvolvedor estava mudando a estrutura do seu JSX de uma forma que fazia o React pensar que todo o componente do formulário da Etapa 2 era um componente novo e diferente. Sem uma prop key estável para identificá-lo, o React destruiu o componente antigo (junto com todo o seu estado, ou seja, os dados inseridos pelo usuário) e montou um novinho em folha em seu lugar.
A lição: A prop key não serve apenas para listas. Ela é uma identidade estável para um componente. Entender como o React usa as keys para rastrear componentes entre as renderizações é crucial para preservar o estado e evitar que ele seja resetado inesperadamente.
O Martelo da API Infinita
Uma equipe estava construindo um dashboard que exibia dados de ações em tempo real. Um desenvolvedor escreveu um componente para buscar o preço mais recente de uma ação específica usando o hook useEffect. O código era mais ou menos assim:
useEffect(() => {
fetchStockPrice(stockSymbol).then(price => {
setPrice(price); // Atualiza o estado com o novo preço
});
}); // Ops, sem array de dependências!
Assim que o componente carregou, o app congelou, a ventoinha do notebook do desenvolvedor disparou e o monitoramento de rede mostrou milhares de requisições idênticas à API sendo disparadas por segundo. Eles haviam criado um loop infinito. O useEffect buscava os dados e chamava setPrice. A atualização do estado causava a re-renderização do componente. Como o useEffect não tinha um array de dependências, ele rodava de novo após cada renderização, buscando os dados novamente, atualizando o estado novamente, causando outra re-renderização, e assim por diante, para sempre.
A lição: Hooks do React como o useEffect são ferramentas poderosas, mas que exigem precisão. Você deve fornecer um "array de dependências" para dizer ao React quando executar novamente o efeito. Deixá-lo de fora significa "rode após toda e qualquer renderização", o que é uma receita para o desastre quando há atualizações de estado.
Erros e armadilhas comuns
- Mutar o estado diretamente. Nunca faça
myState.prop = 'value'oumyArray.push('item'). A detecção de mudanças do React depende da identidade de objetos e arrays. Ao chamarsetState, você deve fornecer um novo objeto ou array (ex: usando a sintaxe de spread...) para que o React perceba a mudança. - Esquecer das
keys em listas. Ao renderizar uma lista de itens usando.map(), você deve dar a cada elemento uma propkeyúnica e estável (comoitem.id). É assim que o algoritmo de diffing do React consegue rastrear eficientemente quais itens se moveram, foram adicionados ou removidos. Usar o índice do array como key é um antipadrão comum que pode levar a bugs. - Tratar JSX como HTML. É parecido, mas não é a mesma coisa. Você tem que usar
classNameem vez declass,htmlForem vez defor, e camelCase para propriedades de estilo (backgroundColore nãobackground-color). Além disso, todas as tags devem ser fechadas, então uma imagem é<img ... />, e não<img>. - Achar que os hooks são mágicos. Hooks como
useStateeuseEffectseguem regras estritas (ex: só podem ser chamados no nível mais alto de um componente de função). Eles funcionam baseando-se em uma ordem de chamada consistente entre as renderizações. Tentar chamá-los dentro de loops ou condicionais vai quebrar sua aplicação.
Por que isso deve estar no seu radar
O React não é apenas uma biblioteca; é um ecossistema e uma forma de pensar. Ele move uma porção gigantesca da web moderna, de sites enormes como Instagram e Netflix a inúmeras startups e ferramentas internas. Aprender React significa aprender uma arquitetura baseada em componentes que promove código reutilizável, testável e de fácil manutenção.
Mesmo que você não use React diariamente, entender seus princípios fundamentais — UI declarativa, gerenciamento de estado e o VDOM — fará de você um desenvolvedor melhor. Esses conceitos influenciaram quase todos os outros frameworks de UI modernos, de Vue a Svelte. Além disso, com o React Native, as mesmas habilidades e princípios podem ser usados para construir aplicativos móveis nativos para iOS e Android. É um paradigma poderoso e essencial para qualquer desenvolvedor que trabalhe com interfaces de usuário hoje em dia.
Para ir mais fundo
- React Docs (Official) - A documentação oficial é o melhor lugar para começar, com um tutorial completo e guias aprofundados.
- Introducing JSX (React Docs) - A explicação oficial sobre JSX e como ele se difere do HTML.
- Reconciliation (React Docs) - O algoritmo que o React usa para comparar duas árvores VDOM e atualizar a UI eficientemente.
- The Rules of Hooks (React Docs) - As regras essenciais que você deve seguir ao usar hooks como
useStateeuseEffect. - MDN: Introduction to the DOM - Para entender o que o React está manipulando, é vital entender o próprio Document Object Model.
Como um editor entende código
As cores vêm de um analisador da linguagem, não da execução do programa. CodeMirror e Lezer reconhecem símbolos e estrutura no navegador. As sugestões combinam palavras-chave, nomes locais quando disponíveis, trechos e uma pequena referência integrada; passar sobre um símbolo documentado revela sua assinatura. Uma sugestão não garante que a API exista no runtime. Os diagnósticos detectam sintaxe malformada quando há suporte, mas não substituem verificação de tipos nem execução: código sintaticamente válido também pode falhar. Ruby e Lua usam modos baseados em tokens, com diagnósticos mais limitados. Não há servidor remoto de linguagem; o código não precisa sair do dispositivo.
CodeMirror & Lezer: MIT.