Pular para o conteúdo
Cursos

DevClub

LógicaFront-endBack-endMobile

IA Club

IA na prática
Estudar programaçãoEstudar IA

Aula 3 de 6

Eventos e estado no React: atualize a tela com useState

Responda a cliques, modele estado com useState e aplique atualizações baseadas no valor anterior sem modificar objetos diretamente.

46 minutos · leitura + prática · nível iniciante

Ao terminar esta aula, você vai conseguir

  • Associar funções a eventos no JSX
  • Atualizar estado com base no valor anterior
  • Manter objetos de estado imutáveis
O componente App se divide nos componentes Header, Lista e Botão.

Você clica em “Adicionar”, mas a quantidade não muda. Ou clica várias vezes e o número avança menos do que esperava. Em outro teste, o valor parece certo, mas um objeto antigo também foi alterado. Esses sintomas diferentes costumam nascer do mesmo ponto: a interface ainda não separou bem o que aconteceu de qual informação precisa mudar.

No React, um evento avisa que algo aconteceu — por exemplo, um clique. O estado guarda a informação que a tela precisa lembrar entre uma interação e outra. A gente precisa dos dois porque uma tela útil não apenas recebe ações: ela também conserva o resultado dessas ações e renderiza a versão mais recente.

Essa dupla aparece em produtos que você já conhece. Na reconstrução do Facebook.com com React, a equipe da Meta descreveu decisões de navegação e abas de conversa guiadas pelo estado da aplicação. O nosso contador é menor, mas ensina o mesmo caminho: interação, atualização e nova tela.

Se JSX ainda parece novo, volte à aula de componentes, JSX e Vite. Se a dúvida está em como um componente recebe uma ação de outro, revise props e composição.

Por que um botão precisa de evento e estado?

Porque o evento identifica a ação do usuário, enquanto o estado registra o dado que deve sobreviver ao clique. Sem o evento, o componente não sabe quando agir. Sem o estado, ele não tem uma memória própria para atualizar e mostrar.

Pense no placar de uma partida. O botão do operador é o evento; a pessoa que interpreta esse botão faz o papel do handler, a função responsável por tratar a ação; o número registrado é o estado; e o painel iluminado é a interface renderizada. Quando o operador pede “some um”, o sistema atualiza o registro e mostra outro placar. No React, essa solicitação passa pelo setter, a função de atualização devolvida por useState.

A comparação tem um limite: o placar físico parece trocar na mesma hora, mas o React pode enfileirar e agrupar solicitações antes da próxima renderização. Por isso, estado não deve ser tratado como uma variável comum que muda imediatamente no meio da função.

Como fazer o primeiro clique atualizar a tela?

Comece pelo menor exemplo útil: um botão que conta cliques. Ele isola a relação entre evento, estado e nova renderização sem misturar regras de carrinho, validação ou formulário.

jsx
function Contador() {
  const [total, setTotal] = React.useState(0);

  function incrementar() {
    setTotal(total + 1);
  }

  const eventos = { onClick: incrementar };

  return (
    <button type="button" {...eventos}>
      Cliques: {total}
    </button>
  );
}

Leia o exemplo de cima para baixo. Contador é o componente. useState(0) cria o estado inicial 0 e devolve um par: total, que é o valor disponível nesta renderização, e setTotal, que solicita a próxima versão. A função incrementar é o handler; ela pede um total uma unidade maior.

O objeto eventos guarda a propriedade onClick apontando para o handler. No botão, {...eventos} espalha essa propriedade no JSX; o resultado prático é o mesmo vínculo entre o clique e incrementar. type="button" evita que o botão envie um formulário por acidente, e {total} coloca o snapshot atual no texto. Quando setTotal é chamado, React renderiza novamente e esse texto recebe o novo valor. O artigo de eventos no React aprofunda onClick, onChange e o objeto do evento.

Por que três setters podem somar apenas uma vez?

Porque cada renderização entrega um snapshot, uma fotografia do estado naquele momento. Dentro do mesmo handler, total continua com o valor daquela fotografia. Se três atualizações calcularem total + 1, as três podem partir do mesmo número, em vez de formar uma sequência.

Quando o próximo estado depende do anterior, passe ao setter uma função atualizadora:

jsx
function somarTres() {
  setTotal((atual) => atual + 1);
  setTotal((atual) => atual + 1);
  setTotal((atual) => atual + 1);
}

Aqui, somarTres reúne três solicitações na mesma ação. Em cada chamada, atual não vem do snapshot fechado no começo do handler: ele representa o valor pendente mais recente da fila. A primeira função soma um, a segunda recebe esse resultado e soma outro, e a terceira repete o processo. Assim, um clique nessa ação produz um acréscimo de três.

Não use a forma funcional por ritual. Use quando o cálculo realmente depende do valor anterior, como incrementar, alternar um booleano ou atualizar um item a partir da coleção atual. Se o novo estado é um valor independente, o setter pode recebê-lo diretamente.

Como atualizar um objeto sem apagar ou corromper dados?

Crie um novo objeto para o próximo estado. O nome técnico dessa regra é imutabilidade: em vez de modificar o valor que pertence ao snapshot atual, a gente produz outra referência com a mudança desejada.

O terceiro exemplo mostra o erro:

jsx
item.quantidade += 1;
setItem(item);

Na primeira linha, += 1 altera quantidade dentro do próprio objeto item. Na segunda, setItem(item) entrega ao React a mesma referência que já estava no estado. Além de dificultar a identificação da mudança, a alteração também contamina o snapshot anterior. Quando esse padrão aparece, não é seguro concluir que a tela sempre produzirá um resultado específico; o problema é justamente o comportamento deixar de ser previsível.

O quarto exemplo faz a correção criando um objeto novo:

jsx
setItem((atual) => ({
  ...atual,
  quantidade: atual.quantidade + 1,
}));

setItem recebe uma função porque a nova quantidade depende do objeto atual. Os parênteses depois da seta permitem devolver o objeto diretamente. O spread ...atual copia as propriedades existentes, e quantidade vem depois para substituir somente essa propriedade. O resultado é uma nova referência com o mesmo nome e a quantidade seguinte.

Essa cópia é rasa: se houvesse um objeto dentro de item, o nível interno alterado também precisaria ser recriado. Muitas camadas podem ser um sinal de que o estado deve ser simplificado. Veja mais casos com arrays e objetos em estado imutável no React.

Como levar o contador mínimo para um carrinho?

O contador ensinou uma regra isolada. O laboratório transforma essa regra em uma funcionalidade reconhecível: a quantidade de uma camiseta no carrinho. item reúne nome e quantidade; aumentar e diminuir são handlers; as duas funções usam o objeto mais recente e devolvem outro objeto. Em diminuir, Math.max protege o limite mínimo. Os dois botões passam referências de função ao onClick, sem executá-las durante a renderização.

O parágrafo com aria-live="polite" anuncia mudanças de quantidade para tecnologias assistivas sem interromper a pessoa. Isso mostra a subida do exemplo mínimo para uma decisão de produto: não basta o número mudar; a interação precisa respeitar limites e comunicar o resultado.

Guarde somente o estado necessário. Se o subtotal sempre é preço vezes quantidade, calcule-o durante a renderização. Salvar quantidade e subtotal cria duas fontes de verdade que podem divergir. Essa mesma regra volta quando você construir um formulário controlado: o estado deve representar o dado, não cópias desnecessárias dele.

Por que o evento pode disparar antes do clique?

Ao escrever onClick={incrementar()}, os parênteses chamam a função durante a renderização. O evento deixa de receber uma função para usar no clique; se essa chamada agenda estado, outra renderização pode chamar tudo novamente. O conserto é passar a referência onClick={incrementar}. Para reconhecer o erro, olhe primeiro para o valor entregue ao onClick: precisa ser uma função, não o resultado de uma chamada.

Outro erro é mutar objeto ou array e depois passar a mesma referência ao setter. O conserto é criar o próximo valor com spread, map ou filter, conforme o tipo de dado. Não decore uma ferramenta isolada; procure a regra: o snapshot atual permanece intacto e o próximo estado recebe uma nova referência.

O que você leva para a próxima aula?

  • Evento informa o que aconteceu; handler decide a atualização.
  • Estado é a memória da interface naquela renderização.
  • Função atualizadora é a escolha segura quando o próximo valor depende do anterior.
  • Objetos e arrays de estado são substituídos, não mutados.
  • Valores derivados, como subtotal, não precisam virar outro estado.

Feche com a missão do placar: cinco cliques rápidos devem produzir 5; zerar deve produzir 0; repetir a sequência não pode perder cliques; e nenhuma atualização pode modificar diretamente um objeto de estado. Esse teste verifica comportamento, não uma saída inventada.

Na aula 4, você aplicará o mesmo raciocínio a uma coleção: criar um novo array, preservar a identidade de cada item e derivar filtros. Continue em listas, filtros e keys.

Laboratório ao vivo

Controle de quantidade do carrinho

Use os botões para alterar a quantidade. Depois limite o máximo a cinco e confirme que diminuir em zero nunca produz valor negativo.

Pronto para testar
Resultado

Pare e pense

Quando o próximo estado depende do estado anterior, qual forma é mais segura?

Escolha uma resposta
Missão da aula

Faça sem copiar

Construa um placar com botões +1 e zerar. A missão passa se cinco cliques rápidos produzem 5, zerar produz 0 e nenhum objeto de estado é alterado diretamente.

Fontes para consultar

Terminou a missão?

Marque apenas quando você conseguir explicar o conceito e concluir o desafio. O progresso fica salvo somente neste navegador.

Próxima: Listas, keys e filtros no React →