Saltar al contenido principal

React Router

Para crear aplicaciones en React que estén compuestas de varias pantallas necesitamos un enrutador.

Un enrutador nos permite relacionar URL's con componentes.

React no incluye un enrutador pero podemos utilizar una liberaría llamada React Router.

Nota: en esta sección vamos a utilizar la versión 6 de React Router.

El primer paso para utilizar React Router es instalar la librería.

Con npm:

$ npm install react-router-dom@6 history@5

Con Yarn:

$ yarn add react-router-dom@6 history@5

Para utilizar React Router en tu proyecto primero debes importarlo y utilizar los componentes BrowserRouter, Routes y Route para definir las rutas, por ejemplo:

import React, { Component } from 'react';
import { BrowserRouter, Routes, Route } from "react-router-dom";
...

function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="about" element={<About />} />
</Routes>
</BrowserRouter>
);
}

En este caso, cuando ingresen a la raíz de nuestro proyecto (/) se renderizará el componente Home y cuando ingresen a /about se renderizará el componente About.

Para crear vínculos a las rutas de la aplicación sin refrescar la página utiliza el componente Link. Por ejemplo, podemos crear un menú que nos permita navegar al Home y al About:

import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
...

function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Routes>
...
</Routes>
</BrowserRouter>
);
}

Plantillas (template)

Para definir una plantilla que podamos usar en varias pantallas de nuestra aplicación puedes crear rutas anidadas de la siguiente forma:

function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Template />}>
<Route index element={<Home />} />
<Route path="about" element={<About />} />
</Route>
</Routes>
</BrowserRouter>
);
}

Lo primero es definir una ruta que va a definir el template y rutas anidadas que van a utilizar ese template. En este caso nuestro template va a ser definido por un componente llamado Template.

La ruta index se utiliza para definir el componente que se va a mostrar por defecto cuando alguien ingrese al path definido en la padre (en este caso a la raíz del proyecto /).

El componente Template se definiría de la siguiente forma:

import { Outlet } from 'react-router-dom';

function Template() {
return (
<div>
<h1>Mi Super Aplicación</h1>
<Outlet />
</div>
);
}

Cada componente como Home y About se va a renderizar dentro del componente Outlet. El <h1> aparecerá en todas las páginas.

Ruta No Encontrada

Puedes agregar una ruta por defecto cuando ninguna otra ruta coincida:

import { BrowserRouter, Routes, Route } from "react-router-dom";
...

function App() {
return (
<BrowserRouter>
<Routes>
...
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}

Parámetros de Ruta

Puedes crear rutas dinámicas con parámetros de ruta.

Los parámetros de ruta son variables que puedes utilizar dentro de la ruta.

Los parámetors de ruta se definen empezando con dos puntos seguidos del nombre de la variable. Por ejemplo:

<Route path="/hello/:name" element={<Greet />}>

Esta ruta coincidiría con cualquier URL que comience con /hello/ seguido de cualquier otro string (que no contenga /), por ejemplo /hello/pablo o /hello/maria. Pero no coincidiría con /hello/pedro/perez.

Los parámetros de ruta se pueden acceder dentro del componente utilizando el hook useParams:

import { useParams } from "react-router-dom";

function Greet() {
const params = useParams();
return <h1>Hola {params.name}</h1>;
}

Dependiendo del valor que llegue en el parámetro de ruta name se mostraría un saludo diferente. Por ejemplo, para /hello/pedro se mostraría el texto "Hola pedro" dentro del h1.

En una sección anterior de esta guía vimos cómo navegar de forma declarativa utilizando el componente Link. En esta sección vamos a ver cómo forzar la navegación desde nuestro código.

La primera forma es utilizar el componente Navigate, que redirecciona al usuario cuando se renderiza. Por ejemplo, podemos utilizar este componente para redireccionarlo a la página de ingreso si no está autenticado:

import { Navigate } from "react-router-dom";

function App() {
const authenticated = ...;
return (
{ authenticated ? <h1>Bienvenido</h1> : <Navigate to="/login" /> }
)
}

La otra forma es utilizar el hook useNavigate, que podemos invocar en nuestro código cuando necesitemos redireccionar al usuario a otra ruta. Por ejemplo, podemos utilizar useNavigate para redireccionar al usuario después de la autenticación:

import { useNavigate } from "react-router-dom";

function Login() {
const navigate = useNavigate();

function handleSubmit() {
// autenticamos al usuario
navigate("/") // lo redireccionamos
}

return <form onSubmit={handleSubmit}>...</form>
}

Rutas Privadas

Para implementar rutas privadas (rutas que sólo usuarios autenticados pueden acceder) necesitamos crear un componente adicional que llamaremos RequireAuth y que se configurará en la ruta de la siguiente forma:

<Route 
path="/private"
element={
<RequireAuth>
<ProtectedPage />
</RequireAuth>
}
>

El componente RequireAuth se implementaría de la siguiente forma:

import { useLocation } from 'react-router-dom';

function RequireAuth({ children }) {
const location = useLocation();
const authenticated = ... // verificar si el usuario está autenticado
return authenticated ? children : <Navigate to="/login" state={{ from: location }} />
}

La idea general de este componente es verificar si el usuario está autenticado y renderizar el componente protegido o redireccionar al usuario a la página de ingreso.

Nota: En este ejemplo hemos omitido el código que verifica si el usuario está autenticado porque depende de la forma en que se implemente (p.e. esta información puede estar en el Context API, en Redux, o directamente en el LocalStorage, entre otras).