O fluxo: adicionar, listar, marcar, apagar
No React os dados fluem para baixo (de pais para filhos, via props) e os eventos sobem (um filho avisa o pai chamando uma função que o pai lhe passou). Vejamos o ciclo completo do nosso app.
1. O estado vive em App
function App() {
const [tarefas, setTarefas] = useState([]);
const [texto, setTexto] = useState("");
// ...
}
tarefas: o array de tarefas.texto: o que o usuário vai digitando (input controlado).
2. Adicionar com um input controlado + botão
Um input é controlado quando seu value é definido pelo estado e cada tecla
atualiza esse estado com onChange. Ao clicar em "Adicionar", criamos uma tarefa nova
e a concatenamos sem mutar o array anterior:
<input value={texto} onChange={(e) => setTexto(e.target.value)} />
<button onClick={adicionar}>Adicionar</button>
function adicionar() {
if (texto.trim() === "") return; // não adicionar vazios
const nova = { id: Date.now(), texto, feita: false };
setTarefas([...tarefas, nova]); // cópia + a nova
setTexto(""); // limpa o input
}
Nunca faça
tarefas.push(...): mutar o array não avisa o React. Crie um novo com[...tarefas, nova]e passe-o parasetTarefas.
3. Listar (passar o array para baixo)
<ListaTarefas tarefas={tarefas} />
E dentro, um <li> por tarefa, com key estável (o id):
function ListaTarefas({ tarefas }) {
return (
<ul>
{tarefas.map((t) => (
<li key={t.id}>
<TarefaItem tarefa={t} />
</li>
))}
</ul>
);
}
4. Marcar como feita (os eventos sobem)
Para marcar uma tarefa, o pai define como se faz e os filhos só
avisam. Mapeamos o array e devolvemos uma cópia com feita alterado na
tarefa correta:
function concluir(id) {
setTarefas(tarefas.map((t) =>
t.id === id ? { ...t, feita: !t.feita } : t
));
}
Com essas peças você tem um app completo. Nos exercícios você o construirá
de baixo para cima: primeiro TarefaItem, depois ListaTarefas e por último a
App que junta tudo.