En esta clase te propongo varios ejercicios para mejorar la aplicación de empleos que hemos estado construyendo. Son mejoras que te permitirán practicar conceptos importantes y hacer la aplicación más profesional.
Introducción a las mejoras posibles
Aunque la aplicación ya funciona correctamente, todavía hay espacio para añadir más funcionalidades que mejoren la experiencia de usuario y te permitan practicar conceptos avanzados de React.
Estos ejercicios están diseñados para que los resuelvas por tu cuenta, aplicando todo lo que has aprendido hasta ahora.
Ejercicio 1: Botón de “Limpiar filtros”
Descripción
Añade un botón que permita limpiar todos los filtros aplicados de una sola vez.
Requisitos
1. El botón solo debe aparecer cuando hay filtros activos
El botón no debe mostrarse si no hay ningún filtro aplicado. Esto significa que debes:
- Crear una función o helper que determine si hay filtros activos
- Usar renderizado condicional para mostrar/ocultar el botón
Pista: Necesitas crear una función que verifique si alguna propiedad del objeto filters no está vacía. Piensa en usar operadores lógicos (||) o métodos como Object.values().
2. Implementar handleClearFilters
Debes crear una función que:
- Limpie todos los filtros
- Resetee el estado a los valores iniciales
- Opcionalmente, también podría resetear la paginación
Pista: Esta función debe llamar a setFilters con un objeto que tenga todas las propiedades vacías. Considera si también quieres resetear otros estados como la página actual.
3. Mostrar el botón solo cuando corresponda
El botón solo debe aparecer en el DOM cuando realmente haya filtros activos.
Pista: Usa el operador && para renderizado condicional: {condicion && <Componente />}
Conceptos implicados
- Renderizado condicional
- Gestión del estado
- Mejora de UX
- Funciones helper
Pistas
- Piensa en qué significa “filtros activos”
- El botón debería resetear todo al estado inicial
- Considera si también quieres resetear la página actual
Ejercicio 2: Mostrar un spinner de carga
Descripción
Mejora la experiencia de carga sustituyendo el texto simple por un spinner visual más atractivo.
Requisitos
1. Crear un componente Spinner
Pista: Crea un componente que devuelva un div con una clase CSS. Para la animación:
- Usa
border-radius: 50%para hacer un círculo - Usa
bordercon diferentes colores (uno diferente para el borde superior) - Crea una animación
@keyframesque rote de 0 a 360 grados - Aplica la animación con
animation: nombre-animacion duración linear infinite
2. Reemplazar el texto de carga
Pista: En lugar de mostrar solo texto cuando loading es true, devuelve un contenedor que incluya:
- Tu componente
<Spinner /> - Un mensaje de texto descriptivo
- Estilos CSS para centrarlo en la página
Conceptos implicados
- Componentes reutilizables
- Animaciones CSS
- Mejora de UX
- Feedback visual
Pistas
- Puedes encontrar muchos ejemplos de spinners CSS en internet
- También puedes usar una librería como
react-spinners - Asegúrate de que el spinner esté centrado y sea visible
Ejercicio 3: Guardar filtros en LocalStorage
Descripción
Persiste los filtros del usuario usando localStorage, de forma que cuando recargue la página, los filtros se mantengan.
¿Qué es LocalStorage?
localStorage es una API del navegador que permite guardar datos de forma persistente. Los métodos principales son:
localStorage.setItem(clave, valor)- Guardar datoslocalStorage.getItem(clave)- Leer datoslocalStorage.removeItem(clave)- Eliminar datoslocalStorage.clear()- Limpiar todo
Importante: localStorage solo acepta strings, así que necesitas:
- Usar
JSON.stringify(objeto)antes de guardar - Usar
JSON.parse(string)después de leer
Requisitos
1. Guardar filtros cada vez que cambien
Pista: Usa un useEffect con filters como dependencia. Dentro del efecto:
- Convierte el objeto
filtersa string conJSON.stringify() - Guárdalo en localStorage con una clave descriptiva (ej: ‘jobFilters’)
2. Leer filtros al cargar la app
Pista: Usa la inicialización “lazy” de useState pasándole una función:
useState(() => { ... })- La función solo se ejecuta una vez al montar- Dentro, intenta leer de localStorage con
getItem() - Si existe, usa
JSON.parse()para convertirlo de string a objeto - Si no existe, devuelve el objeto inicial con valores vacíos
3. Limpiar el localStorage al limpiar filtros
Pista: En tu función handleClearFilters, además de resetear el estado, usa localStorage.removeItem() con la misma clave que usaste para guardar.
Conceptos implicados
- Persistencia de datos
- API del navegador
useEffectcon dependencias- Lazy initialization del estado
- Serialización/deserialización de datos
Pistas adicionales
- Usa la forma de función en
useStatepara la inicialización - Recuerda que
localStorage.getItem()devuelvenullsi no existe la clave - Importante: Envuelve todo en
try-catch-JSON.parse()puede fallar si los datos están corruptos - Considera guardar también la página actual si quieres una experiencia más completa
- Puedes crear un custom hook
usePersistedFilterspara encapsular toda esta lógica
Ejercicio 4: Manejo de errores
Descripción
Actualmente la aplicación no gestiona adecuadamente los errores que pueden ocurrir al hacer peticiones a la API. Es momento de mejorar esto.
Requisitos
1. Añadir estado para errores
Pista: Crea un nuevo estado con useState inicializado en null para almacenar los mensajes de error.
2. Capturar errores en el fetch
Pista: En tu useEffect donde haces el fetch:
- Envuelve todo en un bloque
try-catch-finally - En el
try:- Resetea el error a
nullal inicio - Verifica
response.ok- si esfalse, lanza un error conthrow new Error() - Procesa la respuesta normalmente
- Resetea el error a
- En el
catch: guarda el mensaje de error en el estado - En el
finally: actualiza el estado deloadingafalse(se ejecuta siempre)
3. Mostrar mensajes de error al usuario
Pista: Usa renderizado condicional para mostrar un mensaje cuando error no sea null:
- Muestra un título descriptivo
- Muestra el mensaje de error del estado
- Incluye un botón para reintentar (puede recargar la página con
window.location.reload()o resetear el estado)
4. Diferentes tipos de errores (Bonus)
Pista: Para una mejor experiencia, crea una función helper que devuelva mensajes personalizados según el tipo de error:
- Usa
navigator.onLinepara detectar si hay conexión a internet - Verifica el código de estado HTTP (404, 500, etc.) en el mensaje de error
- Devuelve mensajes claros y accionables para el usuario
- Ten un mensaje genérico como fallback
Conceptos implicados
- Manejo de errores asíncronos
- Try-catch
- Estados de error
- Feedback al usuario
- UX en casos de error
Pistas
- Siempre verifica
response.okantes de procesar la respuesta - Proporciona mensajes de error claros y útiles
- Ofrece una forma de recuperarse del error (botón de reintentar)
- Considera usar
ErrorBoundarypara errores de React
Resumen de los ejercicios
| Ejercicio | Dificultad | Conceptos principales |
|---|---|---|
| Botón limpiar filtros | ⭐⭐ | Renderizado condicional, gestión del estado |
| Spinner de carga | ⭐ | Componentes, CSS, UX |
| Persistencia con localStorage | ⭐⭐⭐ | localStorage, useEffect, serialización |
| Manejo de errores | ⭐⭐⭐ | Try-catch, estados de error, UX |
Bonus: Combinación de mejoras
Una vez completados todos los ejercicios, tendrás una aplicación mucho más robusta:
✅ Filtros persistentes - El usuario no pierde sus filtros al recargar
✅ Mejor feedback visual - Spinners en lugar de texto simple
✅ Fácil limpieza de filtros - Un solo clic para resetear todo
✅ Manejo robusto de errores - La app no se rompe ante problemas de red
Consejos finales
Para el botón de limpiar filtros
- Piensa en dónde colocarlo visualmente (junto a los filtros, en la barra de búsqueda, etc.)
- Considera añadir un contador de filtros activos (“3 filtros aplicados”)
Para el spinner
- No abuses de las animaciones (pueden distraer)
- Asegúrate de que sea accesible (añade
aria-label) - Considera diferentes estados (cargando, éxito, error)
Para localStorage
- Ten cuidado con el tamaño de los datos (localStorage tiene límites)
- Siempre maneja el caso de que el usuario tenga localStorage deshabilitado
- Considera usar un prefijo para las claves (
jobApp_filtersen lugar de solofilters)
Para el manejo de errores
- Sé específico en los mensajes de error
- Proporciona acciones claras al usuario
- No muestres errores técnicos al usuario final
- Registra los errores en la consola para debugging
Conclusión
Estos ejercicios te permitirán practicar conceptos avanzados de React y mejorar significativamente la experiencia de usuario de tu aplicación.
No te preocupes si no consigues resolverlos todos a la primera. Estos son ejercicios de nivel intermedio-avanzado que requieren investigación y prueba-error.
Lo importante es:
- Intentarlo por tu cuenta antes de buscar soluciones
- Investigar cuando te quedes atascado
- Entender por qué funciona la solución
- Experimentar con variaciones
💡 Tip: Implementa cada mejora por separado y asegúrate de que funciona antes de pasar a la siguiente. Es mejor hacer las cosas paso a paso que intentar hacerlo todo a la vez.
¡Manos a la obra! 🚀