En este laboratorio vas a practicar formularios controlados en React. La aplicacion ya tiene el listado de tareas funcionando: lee las tareas desde un servicio asincrono, las pinta y se "recarga" cuando se le pide. Tu trabajo es construir el formulario que aparece arriba del listado para que el usuario pueda crear nuevas tareas.
Vas a practicar:
- Inputs controlados: mapear
valueyonChangea unuseState. - Submit handler: usar
event.preventDefault()y llamar a un servicio asincrono. - Comunicacion hijo → padre: recibir una funcion como prop (
reloadTasks) y llamarla cuando proceda.
npm install
npm run devAbre el navegador en la URL que indique Vite (normalmente http://localhost:5173).
Deberias ver una pagina con:
- Una barra superior Iron Tasks.
- Una card vacia donde aun no hay formulario (es lo que vas a construir).
- Un listado con 3 tareas ya creadas.
src/
├── App.jsx
├── main.jsx
├── index.css
├── pages/
│ └── home-page.jsx ← orquesta el estado y le pasa reloadTasks al form
├── components/
│ ├── ui/
│ │ └── navbar/ ← navbar simple
│ └── tasks/
│ ├── task-form/ ← VACIO, lo construyes tu
│ ├── task-list/ ← ya hecho
│ └── task-item/ ← ya hecho
└── services/
└── tasks-service.js ← getTasks y addTask (asincronos)
src/services/tasks-service.js ya esta hecho. Expone dos funciones asincronas que simulan una API real con un pequeño retardo:
getTasks()→ devuelve una promesa que resuelve a un array de tareas.addTask(task)→ recibe un objeto tarea, lo añade al "backend" y devuelve la tarea creada.
Una tarea tiene esta forma:
| Campo | Tipo | Valores |
|---|---|---|
title |
string | El titulo de la tarea |
description |
string | Descripcion larga |
priority |
string | 'low', 'medium' o 'high' |
deadline |
string | Fecha en formato yyyy-mm-dd |
category |
string | 'work', 'personal' o 'study' |
⚠️ Las dos funciones sonasync. Tendras que usarawait(o.then) cuando las llames.
Mira src/pages/home-page.jsx. Es donde vive el estado de la lista de tareas. Es tambien quien le pasa al TaskForm la prop reloadTasks.
Lee el codigo despacio. Entiende quien tiene el estado, quien lo cambia y quien se entera de los cambios antes de seguir.
Abre src/components/tasks/task-form/task-form.jsx. Borra el placeholder y crea el JSX del formulario.
Debe tener un input o select por cada campo de una tarea:
| Campo | Tipo de input recomendado |
|---|---|
title |
<input type="text"> |
description |
<textarea> |
priority |
<select> con tres opciones |
deadline |
<input type="date"> |
category |
<select> con tres opciones |
Acaba con un <button type="submit"> y envuelve todo en un <form>.
💡 Usa clases de Bootstrap (
form-control,form-select,mb-3,btn btn-primary...) para que se vea decente sin escribir CSS.
En este punto el formulario se ve pero no hace nada. Esta bien — lo arreglamos en la siguiente iteracion.
Cada input necesita un estado que represente su valor.
- Declara un
useStatepor cada campo. - En cada input/select, conecta dos cosas:
valueapunta al estado, yonChangellama al setter pasando elevent.target.value.
💡 Tip para debug: mientras desarrollas, pinta los estados en pantalla con un
<pre>{JSON.stringify(...)}</pre>arriba del formulario. Veras en tiempo real como cambian al escribir. Quitalo cuando termines.
Si lo has hecho bien, ahora puedes escribir en los campos y el navegador "deja" que cambien (eso significa que React esta controlando los valores).
Necesitas una funcion handleSubmit asociada al evento onSubmit del <form>. Dentro de esa funcion:
- Llama a
event.preventDefault()(si no, el navegador recarga la pagina). - Llama al servicio
addTaskpasandole un objeto con los datos del formulario. Recuerda que es asincrono. - Limpia los inputs (vuelve cada estado a su valor inicial).
- Llama a
reloadTasks(), que viene como prop desde el padre, para que el listado se refresque.
⚠️ ¿Por que necesitamosreloadTasks? Porque el padre (HomePage) es quien tiene el array de tareas en suuseState. El formulario, despues de crear una tarea, le dice al padre "oye, recarga tu lista". Es comunicacion hijo → padre via callback.
Cuando termines, prueba a crear una tarea desde el formulario. Debe aparecer en la lista de abajo sin recargar la pagina.
Si no lo has hecho aun, acuerdate de destructurar la prop reloadTasks en la firma del componente TaskForm.
El boton de submit deberia estar deshabilitado mientras alguno de los campos obligatorios siga vacio. Asi evitamos enviar tareas con datos incompletos.
Pistas:
- Calcula un booleano
isFormValida partir de los estados (comprueba que los strings no esten vacios —.trim()ayuda a ignorar espacios). - Usa ese booleano en el atributo
disableddel boton. - Piensa que pasa con
priorityycategorysi les das un valor por defecto al inicializar eluseState: ¿necesitan validarse?
💡
disabledacepta un booleano. Cuando estrue, el navegador ignora los clicks y aplica el estilo "atenuado" automaticamente.
addTask tarda un poco (simula latencia de red). Mientras tanto, el usuario no sabe que esta pasando.
- Añade un estado
submitting(booleano). - Ponlo a
truejusto antes de llamar aaddTasky afalsecuando termine. - Usa ese estado para deshabilitar el boton mientras la peticion esta en vuelo y para cambiar su texto (por ejemplo, "Adding...").
💡
try / finallyes util aqui: elfinallyse ejecuta siempre, incluso si la llamada falla, asi te aseguras de no dejar el boton bloqueado para siempre.
En lugar de un useState por campo, prueba a usar un solo estado con forma de objeto, y un solo handleChange que use el atributo name del input para saber que campo actualizar.
Es el patron mas escalable cuando un formulario crece. Practicalo aqui antes de necesitarlo en proyectos mas grandes.
- React — useState
- React — Reacting to input with state
- React — Sharing state between components
- Bootstrap — Forms
Happy coding! ❤️