Navegación
La navegación en una aplicación web es un aspecto fundamental para la experiencia de usuario. En una aplicación de una sola página (SPA), la navegación se realiza sin necesidad de recargar la página, lo que permite una experiencia de usuario más fluida y rápida.
De momento, hemos visto cómo definir rutas en una aplicación React utilizando React Router. Sin embargo, no hemos considerado cómo navegar entre estas rutas, ni cómo pasar información entre ellas.
Enlaces
Para navegar entre rutas en HTML, se utilizan los elementos <a>
con el atributo href
, en el cual se especifica la URL de destino. Sin embargo, en una aplicación que implemente React Router, se debe utilizar el componente Link
para navegar entre rutas.
Este componente se encarga de actualizar la URL del navegador de forma programática accediendo a la API de Historial de navegación de HTML5 que administra el enrutador configurado, BrowserRouter
.
1import { Link } from 'react-router-dom';2
3function Navbar() {4 return (5 <nav>6 <ul>7 <li><Link to="/">Home</Link></li>8 <li><Link to="/products">Products</Link></li>9 <li><Link to="/contact">Contact</Link></li>10 </ul>11 </nav>12 );13}
Como se puede observar, el componente Link
recibe una prop to
que especifica la ruta a la que se desea navegar. Al hacer clic en el enlace, el componente Link
se encargará de actualizar la URL del navegador y renderizar el componente asociado a la ruta especificada (si existe).
En definitiva, el componente Link
renderiza un elemento <a>
con el atributo href
que apunta a la ruta especificada en la prop to
, pero nos brinda un comportamiento optimizado mediante el uso del enrutador configurado.
Configuración de rutas relativas
En un componente Link
, se puede establecer una ruta relativa o absoluta.
-
Una ruta absoluta (que comienza con
/
) se resuelve en relación con la raíz del enrutador, es decir, la URL base de la aplicación. -
Una ruta relativa (que no comienza con
/
) se resuelve en relación con la ruta padre, lo que significa que se basa en la ruta URL que coincidió con la ruta que renderizó eseLink
. Puede contener..
para enlazar a rutas más arriba en la jerarquía. En estos casos,..
funciona exactamente como la funcióncd
de la línea de comandos; cada..
elimina un segmento de la ruta padre.Por ejemplo, si se tiene la siguiente estructura de rutas:
1<Route path="/products" component={Products} />2<Route path="/products/:id" component={ProductDetail} />Y se desea navegar a la ruta
/products
desde la ruta/products/:id
, se puede utilizar un enlace relativo de la siguiente manera:1<Link to="../products">Back to products</Link>Alternativamente, se puede utilizar la prop
relative
para especificar que la ruta es relativa. En este caso, se puede utilizar un componenteLink
con la proprelative="path"
para indicar que la ruta es relativa a la ruta actual, con lo cual sólo se necesita indicar".."
para retroceder un nivel en la jerarquía de rutas.1<Link to=".." relative="path">Back to products</Link>
Propiedad replace
Por otro lado, la prop replace
permite reemplazar la entrada actual en el historial de navegación en lugar de agregar una nueva entrada. Esto puede ser útil en casos en los que no se desea que el usuario pueda regresar a la página anterior.
1<Link to="/products" replace>Products</Link>
De esta manera, si el stack de navegación es /home -> /products -> /products/:id -> /contact
, entonces nos encontramos en la ruta /contact
y, al navegar mediante el componente Link
configurado de la siguiente manera:
1<Link to="/about" replace>2 About3</Link>
El stack de navegación se convertirá en /home -> /products -> /products/:id -> /about
. Es decir, la ruta /contact
se reemplazará por la ruta /about
.
Propiedad state
Por último, la prop state
permite pasar información adicional a la ruta de destino, la cual se puede acceder desde la ubicación de la ruta en el componente asociado.
1<Link2 to="/login"3 state={{ from: "home" }}4 replace5>6 Products7</Link>
En este caso, al navegar a la ruta /login
, se pasará un objeto con la propiedad from
y el valor 'home'
como información adicional. Esta información se puede acceder desde la ubicación de la ruta en el componente asociado.
Enlaces activos
Cabe mencionar que existen otros componentes que representan enlaces en React Router, como NavLink
.
Un NavLink
es un tipo especial de Link
que sabe si está “activo”, “pendiente” o “en transición”. Esto es útil en varios escenarios:
- Al construir un menú de navegación, como un breadcrumb o un conjunto de pestañas donde se desea mostrar cuál de ellos está seleccionado actualmente.
- Proporciona un contexto útil para tecnologías de asistencia como lectores de pantalla.
- Proporciona un valor “en transición” para brindar un control más detallado sobre las transiciones de vista.
1import { NavLink } from 'react-router-dom';2
3<NavLink4 to="/messages"5 className={({ isActive, isPending, isTransitioning }) =>6 [7 isPending ? "pending" : "",8 isActive ? "active" : "",9 isTransitioning ? "transitioning" : "",10 ].join(" ")11 }12>13 Products14</NavLink>
Si bien NavLink
establece ciertos estilos por defecto para los enlaces activos y estos son claramente visibles, se puede personalizar el estilo de los enlaces activos mediante la prop className
. Podemos establecer condicionalmente clases CSS basadas en las propiedades isActive
, isPending
e isTransitioning
, tal como se muestra en el ejemplo anterior.
Redirecciones
En una aplicación web, es común que se deba redirigir al usuario a una ruta diferente. Para ello, se puede utilizar la función redirect
, la cual requiere de un parámetro que especifica la URL de destino.
1import { redirect } from 'react-router-dom';2
3function Home() {4 return (5 <button onClick={() => redirect('/products')}>6 Go to products7 </button>8 );9}
Navegación programática
Si bien la función redirect
es útil en muchos casos, no es la única forma de redirigir a los usuarios. Sse puede utilizar un hook llamado useNavigate
, que devuelve una función que permite navegar programáticamente a una ruta diferente.
1import { useNavigate } from 'react-router-dom';2
3function Home() {4 const navigate = useNavigate();5
6 return (7 <button onClick={() => navigate('/products')}>8 Go to products9 </button>10 );11}
La función devuelta por useNavigate
puede configurarse con parámetros adicionales para tener un comportamiento similar al del componente Link
, como relative
, replace
, state
, entre otros. Por esta razón, useNavigate
es una alternativa más flexible y poderosa que redirect
.
El uso de useNavigate
es generalmente más ventajoso que redirect
, pero si no se requiere una configuración adicional, redirect
es la opción más adecuada.
Estado de una ruta
Cada ruta en React Router tiene asociada cierta información que se puede acceder desde el componente asociado a la ruta. Esta información incluye la ubicación actual, los parámetros de la ruta, el historial de navegación, entre otros.
Location
El término “location” en React Router se refiere a la interfaz Location
de la librería history
, la cual es una dependencia de React Router que proporciona una API para interactuar con el historial de navegación del navegador. La interfaz Location
representa la ubicación actual en la aplicación, incluyendo la URL actual, el historial de navegación, entre otros.
Esta es fundamental para la navegación, ya que es la que permite al enrutador BrowserRouter
saber qué componente debe renderizar en función de la URL actual. Para esto, se vale de un objeto location
que contiene toda esta información.
Por supuesto, podemos interactuar con este objeto accediendo a sus propiedades mediante el hook useLocation
.
1import { useLocation } from 'react-router-dom';2
3function Home() {4 const location = useLocation();5
6 return (7 ...8 );9}
Este cuenta con las siguientes propiedades:
pathname
: la ruta de la URL actual. Por ejemplo, si la URL actual eshttp://localhost:3000/products
, el valor depathname
será/products
.search
: la cadena de consulta de la URL actual. Por ejemplo, si la URL actual eshttp://localhost:3000/products?category=electronics
, el valor desearch
será?category=electronics
. Esta propiedad es accesible también mediante el hookuseParams
.hash
: el fragmento de la URL actual. Por ejemplo, si la URL actual eshttp://localhost:3000/products#top
, el valor dehash
será#top
. Este fragmento se utiliza comúnmente para enlazar a una sección específica dentro de un mismo componente.state
: La información adicional que se pasó a la ruta de destino mediante la propstate
de un componenteLink
o mediante el hookuseNavigate
.key
: cada ruta cuenta con una clave única que se utiliza para identificarla en el historial de navegación.
Parámetros de ruta
Como vimos anteriormente, las rutas pueden contener parámetros que se utilizan para identificar recursos específicos. Por ejemplo, en la ruta /products/:id
, :id
es un parámetro que se utiliza para identificar un producto específico.
Estos parámetros se pueden acceder desde el componente asociado a la ruta mediante el hook useParams
.
1import { useParams } from 'react-router-dom';2
3function ProductDetail() {4 const { id } = useParams();5
6 return (7 <div>8 <h1>Product detail</h1>9 <p>Product ID: {id}</p>10 </div>11 );12}
El uso de useParams
nos permite evitar un acoplamiento directo entre la URL y el componente, como el que se presenta al acceder a window.location.pathname
o mediante prop drilling.