Ao terminar esta aula, você vai conseguir
- Definir onde cada estado deve morar
- Compor formulário, filtros, resumo e lista
- Verificar criação, conclusão, remoção e estados vazios
O projeto final é um painel de tarefas que adiciona, conclui, remove e filtra
itens. O desafio principal não é escrever mais JSX; é manter uma fonte de verdade
e um fluxo que você consegue explicar. App coordena o estado, enquanto
componentes menores recebem somente os dados e callbacks necessários.
Pense numa central com um quadro único de pedidos. Formulário, contador e lista consultam o mesmo quadro, então não divergem. A comparação termina quando chega à implementação: React trabalha com snapshots imutáveis e fluxo de dados do pai para os filhos, não com pessoas editando simultaneamente um quadro físico.
Desenhe a árvore e localize o estado
Antes do código, separe as responsabilidades:
App
├── FormularioTarefa
├── Filtros
├── Resumo
└── ListaTarefas
└── ItemTarefatarefas é usada pela lista e pelo resumo; filtro altera a lista; o formulário
adiciona ao conjunto. O ancestral comum é App, então o estado mora nele. Os
filhos recebem props. Isso é elevar o estado: mover a fonte de verdade para o
nível que consegue coordenar todos os consumidores.
function App() {
const [tarefas, setTarefas] = React.useState([]);
const [filtro, setFiltro] = React.useState('todas');
const visiveis = filtrarTarefas(tarefas, filtro);
return (
<main>
<FormularioTarefa aoAdicionar={adicionar} />
<Filtros atual={filtro} aoMudar={setFiltro} />
<Resumo tarefas={tarefas} />
<ListaTarefas tarefas={visiveis} aoAlternar={alternar} aoRemover={remover} />
</main>
);
}visiveis é derivado e não precisa de outro estado. O número de pendentes também
é calculado de tarefas. Menos duplicação significa menos combinações inválidas.
Escreva operações imutáveis
Cada ação devolve um novo array. Adicionar usa spread, alternar usa map e
remover usa filter:
function adicionar(titulo) {
setTarefas((atuais) => [
...atuais,
{ id: crypto.randomUUID(), titulo, concluida: false },
]);
}
function alternar(id) {
setTarefas((atuais) => atuais.map((tarefa) =>
tarefa.id === id ? { ...tarefa, concluida: !tarefa.concluida } : tarefa
));
}
function remover(id) {
setTarefas((atuais) => atuais.filter((tarefa) => tarefa.id !== id));
}Essas funções recebem eventos do usuário indiretamente pelos callbacks dos filhos. O id estável conecta a ação à tarefa e também serve como key na lista.
Trate o estado vazio como parte do produto
Uma lista vazia sem explicação parece falha. Se não existem tarefas, diga “Você ainda não criou tarefas”. Se existem tarefas, mas nenhuma corresponde ao filtro, diga “Nenhuma tarefa neste filtro” e ofereça um caminho para mostrar todas. A mensagem deve refletir a causa real.
Use botões reais para ações, label nos campos e texto compreensível além de
ícones. Um resumo com aria-live="polite" pode anunciar a quantidade de
pendentes. Verifique tudo pelo teclado: Tab alcança campo, filtro e botões; Enter
envia o formulário; o foco visível não desaparece.
Persistência não entra no estado apenas por existir. Se você adicionar
localStorage depois, leia uma vez na inicialização e grave quando tarefas
mudarem, tratando JSON inválido. Se integrar uma API, modele também carregamento
e erro. Nesta entrega, manter os dados em memória deixa o foco nos contratos
entre componentes e torna o reinício previsível.
Teste como uma sequência de comportamentos
Execute estes oito testes manuais:
1. Enviar título vazio mostra orientação e não cria item.
2. Um título válido aparece uma vez e limpa o campo.
3. Concluir muda o item e reduz o total de pendentes.
4. Reabrir restaura o item e o total.
5. O filtro pendentes esconde somente os concluídos.
6. O filtro concluídas mostra somente os concluídos.
7. Remover apaga apenas o item escolhido.
8. Todas as ações funcionam pelo teclado e o vazio tem mensagem.Depois rode o build do projeto Vite:
npm run buildO build bem-sucedido prova que módulos e JSX foram processados; não prova os oito comportamentos, por isso as duas verificações se complementam.
Erro comum: duplicar a mesma verdade
Guardar tarefas, tarefasFiltradas e quantidadePendentes como estados
independentes cria três valores que podem discordar. Guarde o conjunto original
e o filtro; derive o restante. Outro erro é colocar o array dentro de cada filho,
fazendo formulário e lista viverem em versões diferentes da aplicação.
No laboratório, faça os oito testes e altere o estado inicial para vazio. O
projeto está concluído quando o resultado é previsível em cada filtro, não perde
itens após atualizações e comunica o vazio. Uma próxima evolução pode persistir
no localStorage ou integrar uma API, sempre tratando carregamento, erro e dados
remotos como estados explícitos.
Laboratório ao vivo
Painel final de tarefas
Cadastre, conclua, filtre e remova tarefas. Depois crie um estado vazio e confirme que a interface explica o resultado em vez de mostrar uma lista muda.
Pare e pense
Onde deve morar o estado compartilhado pelo formulário, resumo e lista?
Elevar o estado ao ancestral comum cria uma fonte de verdade. Os filhos recebem dados e ações por props e permanecem sincronizados.
Faça sem copiar
Entregue o painel com adicionar, concluir, remover e filtrar. A missão passa nos oito testes manuais descritos na aula, inclusive teclado e estado vazio.
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.
Voltar ao curso e ver seu progresso →