Contenido del curso

Rutas privadas y públicas en React

Resumen

Proteger rutas en una aplicación React no se trata solo de validar formularios, también implica que el menú de navegación reaccione al estado de autenticación del usuario. Aquí aprenderás a renderizar enlaces de forma condicional usando un contexto de autenticación, propiedades personalizadas en cada ruta y el hook useAuth, evitando que React crashee al no encontrar datos del usuario.

¿Por qué falla el menú cuando no hay usuario autenticado?

El problema aparece cuando el menú intenta mostrar enlaces como profile o logout sin que exista un auth.user en el contexto. React no encuentra la propiedad username y la aplicación se rompe.

La lógica deseada es simple: si alguien acaba de llegar y aún no se registra, no tiene sentido mostrarle un enlace a su perfil porque esa cuenta no existe. Y al revés, si ya hizo login, mostrarle otra vez el enlace de login sobra.

¿Qué hace el hook useAuth? Devuelve el contexto de autenticación con la propiedad auth.user, que será un objeto si el usuario está logueado o null si no lo está [02:40].

¿Cómo marcar rutas privadas con una propiedad personalizada?

La estrategia consiste en agregar una propiedad private a cada ruta dentro del array de rutas. Por defecto todas reciben private: false, lo que las vuelve públicas, y solo a las rutas que requieren autenticación se les asigna private: true.

En el ejemplo del transcript, se marcaron como privadas:

  • La ruta de profile.
  • La ruta de logout.

Esto deja al resto como rutas accesibles sin importar el estado del usuario. La idea es que el menú lea esa propiedad y decida si renderiza o no cada enlace.

¿Dónde debe vivir el componente Menú?

Como el menú consume el contexto de autenticación, tiene que estar dentro del AuthProvider. Y para usar componentes como NavLink o hooks como useNavigate y useParams, también debe estar dentro del HashRouter [03:30]. Si lo sacas de ahí, nada funciona.

¿Cómo renderizar condicionalmente cada enlace del menú?

Dentro del routes.map, en lugar de un return implícito directo, abres llaves para escribir lógica antes de retornar el JSX. La pregunta clave es cuándo no renderizar un enlace.

La condición que se evalúa es la siguiente: si la ruta es privada y no existe auth.user, retornas null. En cualquier otro caso, el enlace se renderiza con normalidad [05:10].

js routes.map((route) => { if (route.private && !auth.user) return null; if (route.publicOnly && auth.user) return null; return ( <NavLink to={route.path} key={route.path}> {route.name} </NavLink> ); });

Con esto, al entrar sin sesión solo verás el enlace a login. Al autenticarte, el menú crece y aparecen profile y logout. Al cerrar sesión, vuelve a ocultarlos.

¿Qué pasa si invierto la condición? Si validas cuándo sí renderizar en lugar de cuándo no, terminas con un condicional largo y difícil de leer. Es más limpio retornar null en los casos negativos.

¿Cómo ocultar el enlace de login cuando ya hay sesión activa?

Aquí aparece la segunda capa del problema. Aunque el usuario ya esté autenticado, el enlace a login sigue apareciendo en el menú. Para resolverlo, se introduce una nueva propiedad llamada publicOnly: true en la ruta de login.

Esta propiedad indica que el enlace solo debe verse cuando no hay autenticación. La condición opera al revés que en las rutas privadas: si la ruta es publicOnly y existe auth.user, retornas null.

Después de aplicarlo, el comportamiento queda así:

  1. Sin sesión, solo aparece login en el menú.
  2. Al hacer login, desaparece login y aparecen profile y logout.
  3. Al hacer logout, vuelve a mostrarse únicamente login.

¿Por qué conviene preguntar cuándo NO renderizar?

La solución elegante consiste en escribir condiciones cortas que devuelvan null en los casos prohibidos, en lugar de armar un condicional gigante con múltiples AND y OR para validar cuándo sí mostrar el enlace.

Esto mantiene el código declarativo y fácil de extender. Si mañana agregas una propiedad nueva, solo escribes otro pequeño condicional con su return null correspondiente.

¿Qué falta por proteger en la aplicación?

El menú ya respeta el estado de autenticación, pero la protección es solo visual. Si un usuario escribe manualmente la URL /login estando autenticado, la página sigue cargando. Y si escribe /profile sin estar logueado, la aplicación se rompe porque no encuentra auth.user.

El siguiente paso es implementar redirecciones automáticas: enviar a profile cuando alguien autenticado intente entrar a login, y bloquear el acceso a profile cuando no exista sesión activa.

¿Cómo resolverías tú esa redirección? Cuéntalo en los comentarios con tu enfoque, sin importar si funcionó a la primera o si te enredaste con los condicionales.