Capítulo 3
React: estado e eventos
3 min de leitura 474 palavras 1 gravura
Neste capítulo você vai controlar um contador de vagas com useState e um botão. O projeto-fio é o Ateliê Boa Viagem, ateliê digital fictício em Boa Viagem, Recife.
Seu ponto de partida
Use o exemplo 03-react-estado do pacote anexo e copie inicio/ para uma pasta de prática fora do original. A raiz do exemplo é a referência completa desta etapa.
Use servidor só em 127.0.0.1 quando o README do exemplo pedir HTTP local. Abrir ou testar não publica nada.
Como praticar
Leia → copie ou digite → mude uma coisa → preveja → salve → recarregue → confira. Restaure cada experiência antes da próxima. Faça as atividades antes de abrir as respostas comentadas.

Estado é memória da interface
useState devolve o valor atual e uma função para atualizar. Quando o estado muda, o React redesenha o componente.
Faça na sua cópia
Confira o trecho no contexto do exemplo antes de mudar.
const [vagas, setVagas] = React.useState(8);
Mude uma coisa e preveja
Comece com 3 vagas em vez de 8.
Anote o que espera observar antes de salvar e recarregar.
Recarregue e confira
A página inicia mostrando 3.
Se não acontecer
Importe/use React.useState com o React do CDN já carregado.
Evento dispara atualização
onClick recebe uma função. Não chame setEstado no corpo do render sem condição — isso gera loop.
Faça na sua cópia
Confira o trecho no contexto do exemplo antes de mudar.
<button onClick={() => setVagas(vagas - 1)}>Reservar</button>
Mude uma coisa e preveja
Impida vagas de ficar abaixo de zero.
Anote o que espera observar antes de salvar e recarregar.
Recarregue e confira
Ao chegar em 0, novos cliques não reduzem.
Se não acontecer
Use uma condição antes de setVagas.
Estado derivado com cuidado
Se um valor pode ser calculado a partir de outro, calcule na hora em vez de duplicar estado.
Faça na sua cópia
Confira o trecho no contexto do exemplo antes de mudar.
const esgotado = vagas === 0;
Mude uma coisa e preveja
Mostre Esgotado quando esgotado for verdadeiro.
Anote o que espera observar antes de salvar e recarregar.
Recarregue e confira
A mensagem aparece só com zero vagas.
Se não acontecer
Confira a condição e o texto renderizado.
Atividades
Atividade 1
Para que serve o segundo valor retornado por useState?
Atividade 2
O que acontece se chamar setEstado com o mesmo valor primitivo?
Atividade 3
Cite um estado que deveria ser derivado, não armazenado.
Respostas comentadas
Resposta da atividade 1
Atualizar o estado e pedir novo desenho da interface.
Resposta da atividade 2
Em geral o React pode pular o redesenho.
Resposta da atividade 3
Ex.: esgotado a partir de vagas === 0.
O arquivo completo
Referência do exemplo 03-react-estado, reproduzida aqui para que você possa conferir sem sair da página.
styles.css
:root{--ink:#1a1a1a;--bg:#f7f4ef;--brand:#1f3a5f;--accent:#c45c26;--line:#d9d2c5;--focus:#0b57d0}
*{box-sizing:border-box}html{font-family:"Segoe UI",Tahoma,sans-serif;color:var(--ink);background:var(--bg)}
body{margin:0;line-height:1.5}a:focus-visible,button:focus-visible,input:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
.skip{position:absolute;left:-999px}.skip:focus{left:1rem;top:1rem;z-index:10;background:#fff;padding:.5rem}
header,footer{background:var(--brand);color:#fff;padding:1rem 1.25rem}header a,footer a{color:#fff}
main{max-width:52rem;margin:0 auto;padding:1.25rem}h1{color:var(--brand);margin-top:0}
.card{background:#fff;border:1px solid var(--line);padding:1rem;margin:.75rem 0}
button{background:var(--accent);color:#fff;border:0;padding:.55rem 1rem;cursor:pointer}
.board{display:grid;grid-template-columns:repeat(3,4.5rem);gap:.4rem}
.square{width:4.5rem;height:4.5rem;font-size:1.5rem;background:#fff;border:2px solid var(--brand)}
label{display:block;margin:.5rem 0 .2rem;font-weight:600}
input,textarea{width:100%;max-width:28rem;padding:.45rem;border:1px solid var(--line)}
ul.nav{list-style:none;padding:0;display:flex;gap:1rem;flex-wrap:wrap;margin:0}
.status{font-weight:600;margin:.75rem 0}