Ao terminar esta aula, você vai conseguir
- Conectar value e onChange ao estado
- Tratar o envio no evento submit do formulário
- Exibir validação próxima ao campo e mover o foco quando necessário
Num formulário controlado, o valor exibido pelo campo vem do estado React e cada edição solicita uma atualização desse estado. Isso cria uma fonte de verdade para entrada, validação e envio. O navegador ainda oferece o campo real; React coordena qual valor ele apresenta.
Pense num atendente que repete o pedido no painel enquanto você fala. O painel mostra exatamente o registro atual e pode apontar uma informação incompleta antes de enviar à cozinha. O limite: atualizar estado a cada mudança não substitui validação no servidor. O cliente pode ser alterado ou ignorado, então regras de segurança e integridade precisam existir novamente na API.
Conecte value e onChange
O par fundamental é direto:
function CampoTitulo() {
const [titulo, setTitulo] = React.useState('');
const controle = {
value: titulo,
onChange: (evento) => setTitulo(evento.target.value),
};
return (
<label>
Título
<input {...controle} />
</label>
);
}value recebe o snapshot do estado. Quando a pessoa digita, onChange lê o
novo valor do elemento e chama o setter. React renderiza novamente e o campo
recebe o estado atualizado. Se você fornecer value sem onChange, o campo fica
efetivamente somente leitura.
Trate o envio no formulário
Use o evento submit do <form>, não apenas o clique do botão. Assim Enter no
campo e recursos nativos continuam funcionando:
function enviar(evento) {
evento.preventDefault();
const limpo = titulo.trim();
if (limpo.length < 3) {
setErro('Digite pelo menos 3 caracteres.');
return;
}
setTarefas((atuais) => [
...atuais,
{ id: crypto.randomUUID(), titulo: limpo, concluida: false },
]);
setTitulo('');
setErro('');
}preventDefault evita a navegação padrão da página porque o componente vai
processar o envio. trim remove espaços nas pontas antes da regra. A atualização
funcional preserva tarefas que já estavam no array e acrescenta um objeto novo.
Validação precisa orientar a correção
“Inválido” diz pouco. Informe o critério: “Digite de 3 a 60 caracteres”. Associe
a mensagem ao campo com aria-describedby e use role="alert" para uma falha
que surge depois do envio. Uma borda vermelha pode complementar, mas não deve ser
a única indicação.
<label htmlFor="titulo">Título</label>
const controle = {
value: titulo,
onChange: (evento) => setTitulo(evento.target.value),
'aria-invalid': Boolean(erro),
'aria-describedby': 'erro-titulo',
};
<input id="titulo" {...controle} />
<p id="erro-titulo" role="alert">{erro}</p>Para formulários maiores, mover o foco ao primeiro campo inválido pode ajudar. Faça isso com cuidado para não deslocar a pessoa sem uma ação previsível, como o envio.
Estado temporário e estado definitivo
O texto digitado é estado temporário do formulário; a tarefa só entra na coleção depois de passar pela regra. Não adicione um item vazio para depois tentar consertá-lo. Após sucesso, limpe o campo e o erro. Em uma aplicação com API, também existe estado de envio, sucesso e falha de rede.
Outros controles seguem a mesma ideia com formatos próprios. Uma caixa de
seleção lê evento.target.checked; um <select> lê evento.target.value. Para
um formulário com vários campos, você pode guardar um objeto e copiar as demais
propriedades ao atualizar uma delas. O princípio continua: o estado representa o
valor atual e a regra de envio trabalha sobre um snapshot coerente.
Teste também espaços no começo e no fim. A interface pode preservar o que está
sendo digitado, mas o valor definitivo usa a versão normalizada por trim.
Erro comum: validar um estado antigo
Setters não trocam o valor do snapshot atual imediatamente. Evite chamar
setTitulo(...) e na linha seguinte esperar que titulo já contenha o novo
valor. Valide a variável derivada do evento ou do valor atual, como limpo, e
use esse mesmo valor para criar a tarefa.
No laboratório, envie primeiro espaços, depois dois títulos válidos. A lista precisa manter ambos e o campo deve limpar apenas após sucesso. Na missão, adicione limites mínimo e máximo e mostre quantos caracteres restam. Na próxima aula, reunimos componentes, filtro e formulário no projeto final.
Laboratório ao vivo
Cadastro controlado de tarefa
Envie vazio, depois cadastre duas tarefas. Confirme a mensagem de erro, a limpeza do campo após sucesso e a preservação da primeira tarefa.
Pare e pense
O que torna um campo de formulário controlado no React?
No campo controlado, React recebe o valor atual do estado. O evento onChange atualiza esse estado e mantém tela e dados sincronizados.
Faça sem copiar
Adicione validação de 3 a 60 caracteres e contador do limite. A missão passa quando entradas fora da faixa não entram na lista e o foco continua utilizável.
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: Projeto React: painel de tarefas completo →