El flujo: añadir, listar, marcar, borrar
En React los datos fluyen hacia abajo (de padres a hijos, vía props) y los eventos suben (un hijo avisa al padre llamando a una función que el padre le pasó). Veamos el ciclo completo de nuestra app.
1. El estado vive en App
function App() {
const [tareas, setTareas] = useState([]);
const [texto, setTexto] = useState("");
// ...
}
tareas: el array de tareas.texto: lo que el usuario va escribiendo (input controlado).
2. Añadir con un input controlado + botón
Un input es controlado cuando su value lo manda el estado y cada tecla
actualiza ese estado con onChange. Al pulsar "Añadir", creamos una tarea nueva
y la concatenamos sin mutar el array anterior:
<input value={texto} onChange={(e) => setTexto(e.target.value)} />
<button onClick={agregar}>Añadir</button>
function agregar() {
if (texto.trim() === "") return; // no añadir vacíos
const nueva = { id: Date.now(), texto, hecha: false };
setTareas([...tareas, nueva]); // copia + la nueva
setTexto(""); // limpia el input
}
Nunca hagas
tareas.push(...): mutar el array no avisa a React. Crea uno nuevo con[...tareas, nueva]y pásaselo asetTareas.
3. Listar (pasar el array hacia abajo)
<ListaTareas tareas={tareas} />
Y dentro, un <li> por tarea, con key estable (el id):
function ListaTareas({ tareas }) {
return (
<ul>
{tareas.map((t) => (
<li key={t.id}>
<TareaItem tarea={t} />
</li>
))}
</ul>
);
}
4. Marcar como hecha (los eventos suben)
Para marcar una tarea, el padre define cómo se hace y los hijos solo
avisan. Mapeamos el array y devolvemos una copia con hecha cambiado en la
tarea correcta:
function completar(id) {
setTareas(tareas.map((t) =>
t.id === id ? { ...t, hecha: !t.hecha } : t
));
}
Con estas piezas tienes una app completa. En los ejercicios la construirás
de abajo arriba: primero TareaItem, luego ListaTareas y por último la
App que lo une todo.