Ejercicios de refuerzo: detalle, paginación y filtros
Contexto de la clase
En esta clase no añadimos una gran pieza nueva a la aplicación, sino que dejamos ejercicios de refuerzo para que termines de consolidar todo lo que hemos visto hasta ahora:
- Página de detalle de trabajo
- Navegación y estado activo en los enlaces
- Paginación de resultados
- Sincronización de filtros con la URL usando
URLSearchParamso la API del router
La idea es que, al acabar estos ejercicios, tu aplicación se sienta mucho más pulida y coherente con lo que ya hemos construido.
Ejercicio 1 - Mejorar la página de detalle de trabajo
En el vídeo comento que la página de detalle “está bastante bien, pero hay que arreglarle los estilos totalmente”. El objetivo es que la página deje de parecer un prototipo y se convierta en una vista que podrías enseñar a alguien sin pedir perdón.
Objetivos del ejercicio
- Pulir el diseño visual de la página de detalle de trabajo.
- Asegurarte de que la información importante se lee bien y rápido.
- Mantener consistencia con el listado y el resto de la aplicación.
Puntos a trabajar
Jerarquía visual
- Título del puesto bien destacado (tamaño, peso de fuente).
- Subtítulo con empresa, ubicación y tipo de contrato.
- Secciones claras para descripción, requisitos, beneficios, etc.
Layout
Usa un layout que se adapte bien a escritorio y móvil.
Por ejemplo, en escritorio puedes tener:
- Columna principal con descripción
- Columna lateral con datos clave (salario, ubicación, botón de aplicar)
Tipografía y espaciado
- Ajusta márgenes y paddings para que el contenido respire.
- Asegúrate de que no haya bloques de texto muy densos sin separación.
Botones y acciones
- El botón de “Aplicar” debe ser muy visible.
- Si hay acciones secundarias (guardar, compartir, volver al listado), que se vean pero no compitan con la principal.
Responsive
- En móvil, asegúrate de que todo sea legible sin hacer zoom.
- Comprueba que no haya scroll horizontal raro.
💡 Pista
Puedes hacer una pequeña revisión de diseño:
- Mirar la página durante 5 segundos
- Preguntarte: “¿Qué se entiende primero?, ¿qué sobra?, ¿qué falta?”
Ejercicio 2 - Navegación y estado activo
En el vídeo comento que hay que “implementar bien los breaks” y detectar cuando estemos en esa página para que cualquier enlace de navegación refleje que estamos ahí.
Aquí puedes plantearlo como dos subejercicios opcionales, dependiendo de cómo esté tu proyecto:
2.1. Breadcrumbs de navegación (opcional pero recomendable)
Objetivo: que el usuario sepa en qué parte de la aplicación está.
💡 Pista sobre estructura
Un breadcrumb típico podría verse así en JSX:
<nav aria-label="Ruta de navegación">
<ol>
<li>{/* Enlace a la lista de ofertas */}</li>
<li aria-current="page">{/* Título del trabajo actual */}</li>
</ol>
</nav>
Puntos importantes
- Los breadcrumbs ayudan a la UX mostrando la jerarquía de navegación
- Usa
aria-labelyaria-currentpara mejorar la accesibilidad - El último elemento del breadcrumb no debería ser un enlace
2.2. Marcar el enlace activo en la navegación
En el vídeo también pido que cualquier enlace de navegación detecte si estamos en esa página y se marque correctamente.
Ejercicio
- Usar la información de la URL para marcar como “activo” el enlace correspondiente del menú.
💡 Pista de implementación
Necesitarás:
- Obtener la ruta actual (piensa en hooks del router que has usado)
- Comparar la ruta actual con la ruta del enlace
- Aplicar una clase CSS diferente cuando coincidan
- Añadir
aria-current="page"para accesibilidad
Un patrón común es crear un componente NavLink que envuelva tu componente Link y añada esta lógica.
Ejercicio 3 - Implementar la paginación correctamente
En el vídeo, otro punto clave es “implementar la paginación correctamente”. No es solo mostrar botones de “Siguiente” y “Anterior”, sino que funcione bien en combinación con filtros y URL.
Objetivos
- Tener un componente de paginación reutilizable.
- Sincronizar la página actual con la URL para que:
- Al refrescar se mantenga la página.
- Se pueda compartir la URL con una página concreta.
💡 Esqueleto de componente
Tu componente de paginación debería manejar:
function Pagination({ currentPage, totalPages, onPageChange }) {
// ¿Cuándo se puede ir a la página anterior?
// ¿Cuándo se puede ir a la siguiente?
return (
<nav aria-label="Paginación de resultados">
{/* Botón anterior */}
{/* Indicador de página actual */}
{/* Botón siguiente */}
</nav>
)
}
Integración con la URL
Ejercicio sugerido:
- Guardar la página actual en la query string, por ejemplo
?page=2 - Al cambiar de página, actualizar la URL
- Al cargar la página, leer
pagede la URL y usarlo como estado inicial
💡 Pistas para trabajar con URL
- Puedes usar
URLSearchParamspara leer y modificar los parámetros de la URL window.location.searchte da la query string actual- Para actualizar la URL sin recargar:
window.history.pushState() - O mejor aún, usa los métodos que te proporciona React Router
💡 Ejemplo de lectura de parámetros
// Para leer un parámetro de la URL:
const searchParams = new URLSearchParams(window.location.search)
const pageFromUrl = searchParams.get('page') // devuelve string o null
Ejercicio 4 - Revisar e inicializar todos los filtros desde la URL
En el vídeo remarco que los filtros “funcionan, pero cuando refresco este y este y este no se están inicializando correctamente” y recuerdo que ya hemos visto cómo hacerlo con el filtro de texto. La idea es que apliques la misma lógica al resto de filtros.
Recordatorio de lo visto con el buscador de texto
- Al escribir en el input, actualizábamos la URL.
- Al recargar la página, leíamos la URL para saber el valor inicial del input.
Lo que se pide en el ejercicio
Para cada filtro que tengas (por ejemplo):
- Modalidad (
remote,hybrid,onsite) - Tipo de contrato (
full-time,part-time) - Rango salarial
Debes:
-
Definir un nombre de parámetro en la URL
- Ejemplos:
mode,contract,salaryMin,salaryMax, etc.
- Ejemplos:
-
Al cambiar el filtro en la UI:
- Actualizar el estado en React
- Actualizar la URL con el nuevo valor
-
Al cargar o refrescar la página:
- Leer ese parámetro de la URL
- Inicializar el estado del filtro con ese valor
💡 Pista de implementación
Puedes crear custom hooks para cada filtro siguiendo este patrón:
function useModeFilter() {
const [mode, setMode] = useState('')
// useEffect para leer la URL al montar
// función para actualizar mode y URL
return { mode, updateMode }
}
💡 Pista para actualizar URL
Cuando cambies un filtro:
const updateFilter = (value) => {
// 1. Actualiza el estado local
// 2. Obtén los searchParams actuales
// 3. Si hay valor, añádelo: searchParams.set(name, value)
// 4. Si no hay valor, elimínalo: searchParams.delete(name)
// 5. Actualiza la URL
}
Ejemplo de uso en un componente
function Filters() {
const { mode, updateMode } = useModeFilter()
return (
<select value={mode} onChange={(e) => updateMode(e.target.value)}>
<option value="">Cualquiera</option>
<option value="remote">Remoto</option>
<option value="hybrid">Híbrido</option>
<option value="onsite">Presencial</option>
</select>
)
}
Cierre de la clase
Recapitulación
Estos ejercicios no introducen conceptos totalmente nuevos, pero te obligan a aplicar de verdad lo que hemos visto.
Son perfectos para:
- ✅ Entender cómo se combinan router, URL y estado
- ✅ Pulir la experiencia de usuario de la app
- ✅ Acostumbrarte a pensar en estado inicial a partir de la URL en lugar de inventártelo dentro del componente
Recordatorio importante
- En la próxima clase daré por hecho que esto está hecho
- Cuanto más mimes estos detalles, más se parecerá tu proyecto a una app real y menos a un ejercicio de clase.
- La URL como fuente de verdad es un patrón fundamental en aplicaciones web modernas.
🎯 Checklist de ejercicios
Antes de dar por terminada esta clase, asegúrate de:
- La página de detalle tiene un diseño visual pulido y profesional
- Los breadcrumbs (si los implementas) muestran la ruta de navegación
- Los enlaces del menú principal se marcan como activos correctamente
- La paginación funciona y se sincroniza con la URL
- Todos los filtros se inicializan correctamente desde la URL
- Al refrescar la página, se mantiene el estado de filtros y paginación
- Las URLs son compartibles (contienen toda la información necesaria)