En este módulo evolucionamos la SPA de React hacia una aplicación de producción real. Sustituimos el custom hook de routing por React Router v7, introducimos Zustand para gestionar el estado global de autenticación y favoritos, y añadimos rutas protegidas que redirigen al usuario al login si no ha iniciado sesión. El resultado es una app con flujo completo de autenticación (login, registro, perfil) y la capacidad de guardar empleos favoritos.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/midudev/jscamp/llms.txt
Use this file to discover all available pages before exploring further.
Lo que aprenderás
- React Router v7: configuración de rutas con
<BrowserRouter>,<Routes>y<Route>, navegación programática conuseNavigate, parámetros de URL conuseParamsy query strings conuseSearchParams. - Zustand stores: creación de stores minimalistas con
create()para manejar estado global sin boilerplate. - Context API: uso de
React.createContexty providers como alternativa o complemento a Zustand. - Rutas protegidas: componente
ProtectedRouteque redirige a/loginusando<Navigate>cuando el usuario no está autenticado. - Páginas de login y registro: formularios controlados con
useIdpara accesibilidad, validación y autenticación mock. - Gestión de favoritos: store de Zustand con acciones para añadir, eliminar y verificar empleos favoritos.
Nuevas Dependencias
Las siguientes dependencias se añaden respecto al módulo anterior:| Paquete | Versión | Propósito |
|---|---|---|
react-router | ^7.9.6 | Routing declarativo con soporte para loaders, actions y SSR |
zustand | ^5.0.8 | Gestión de estado global minimalista basada en hooks |
snarkdown | ^2.0.0 | Conversor ligero de Markdown a HTML para renderizar descripciones de empleos |
Zustand: authStore
El store de autenticación (authStore.js) gestiona un único booleano isLoggedIn con dos acciones: login y logout. Su sencillez lo convierte en el ejemplo perfecto para introducir Zustand.
useReducer.
Zustand: favoritesStore
El store de favoritos es más completo: mantiene un array de IDs de empleos y expone varias acciones para manipularlo de forma inmutable.Rutas Protegidas
El componenteProtectedRoute actúa como guardia de rutas privadas. Lee el estado de autenticación desde useAuthStore y, si isLoggedIn es false, redirige automáticamente al usuario a la ruta /login usando el componente <Navigate> de React Router. Si el usuario está autenticado, renderiza el contenido hijo tal cual.
App.jsx basta con envolver el componente de página:
Nuevas Páginas
Este módulo introduce cuatro páginas nuevas respecto al módulo anterior:Detail
Página de detalle de una oferta de empleo. Obtiene el
jobId de los parámetros de URL con useParams y hace fetch a https://jscamp-api.vercel.app/api/jobs/:id. Renderiza la descripción en Markdown usando snarkdown. Muestra el botón “Aplicar ahora” solo si el usuario está autenticado y permite marcar el empleo como favorito con el corazón.Login
Formulario de inicio de sesión con campos de email y contraseña. Usa
useId para generar IDs accesibles dinámicamente. Al enviar, llama a useAuthStore().login() y redirige a /search con useNavigate. La validación es mock (cualquier email+contraseña válidos funcionan).ProfilePage
Página de perfil del usuario autenticado (ruta protegida). Muestra información de perfil demo (nombre, email, experiencia laboral, habilidades). Incluye el botón “Cerrar Sesión” que llama a
useAuthStore().logout().Register
Formulario de registro con campos de nombre, email y contraseña. Al completarse, llama a
login() del store para autenticar inmediatamente al nuevo usuario y redirige a /search. Al igual que Login, usa useId para los atributos id/name de los inputs.Cómo Ejecutar
/login o /register para probar el flujo de autenticación. Una vez autenticado, accede a /profile (ruta protegida) o navega al detalle de cualquier empleo desde la página de búsqueda para ver el botón de favoritos.