Si estás creando aplicaciones React para la web, necesitarás usar un enrutador dedicado para mostrar páginas y navegar por ellas al usuario.

Es por eso que hoy vamos a repasar el enrutador más popular y poderoso para aplicaciones React – React Router.

Vamos a repasar 11 de las características esenciales que necesitas saber si estás usando React Router en tus proyectos, específicamente para la web usando el paquete react-router-dom.

¿Quieres tu propia copia? ?

Haz clic aquí para descargar la hoja de referencia en formato PDF (tarda 5 segundos).

Incluye toda la información esencial como una práctica guía en PDF.

Instala React Router

El primer paso para usar React Router es instalar el paquete apropiado.

Técnicamente, son tres paquetes diferentes: React Router, React Router DOM y React Router Native.

La principal diferencia entre ellos radica en su uso. React Router DOM es para aplicaciones web y React Router Native es para aplicaciones móviles creadas con React Native.

Lo primero que deberás hacer es instalar React Router DOM usando npm (o yarn)

npm install react-router-dom

Configuración básica de React Router

Una vez instalado, podemos traer nuestro primer componente que se requiere para usar React router, que se llama BrowserRouter.

Ten en cuenta que hay varios tipos de enrutadores que proporciona react-enrutador-dom, además de BrowserRouter, en el que no entraremos. Es una práctica común poner un alias (renombrar) BrowserRoute simplemente como 'Router' cuando se importa.

Si queremos proporcionar rutas dentro de toda nuestra aplicación, debe estar envuelto alrededor de todo nuestro árbol de componentes. Es por eso que generalmente lo verás envuelto alrededor o dentro del componente principal de la aplicación:

import { BrowserRouter as Router } from 'react-router-dom';

export default function App() {
  return (
    <Router>
      {/* routes go here, as children */}
    </Router>
  );
}

Esta es la función principal del BrowserRouter: poder declarar rutas individuales dentro de nuestra aplicación.

Ten en cuenta que no se puede acceder a ningún dato específico del enrutador fuera del componente Router. Por ejemplo, no podemos acceder a los datos del historial fuera del enrutador (es decir, con el hook useHistory) y no podemos crear una ruta fuera de un componente Router.

Componente Route

El siguiente componente es el componente Route.

Declaramos rutas dentro del componente Router como secundarias. Podemos declarar tantas rutas como queramos y necesitamos proporcionar al menos dos propiedades para cada ruta, path y component (o render):

import { BrowserRouter as Router, Route } from 'react-router-dom';

export default function App() {
  return (
    <Router>
      <Route path="/about" component={About} />
    </Router>
  );
}

function About() {
  return <>about</>   
}

La propiedad de path especifica en qué ruta de nuestra aplicación se encuentra localizada una ruta determinada.

Para una página acerca de, por ejemplo, podríamos querer que esa ruta sea accesible en el path '/ about'.

Las propiedades render o component se utilizan para mostrar un componente específico para nuestra ruta.

Las propiedades de component solo pueden recibir una referencia a un componente dado, mientras que render se usa más típicamente para aplicar alguna lógica condicional para renderizar un componente u otro. Para renderizar, puede usar una referencia a un componente o usar una función:

import { BrowserRouter as Router, Route } from "react-router-dom";

export default function App() {
  return (
    <Router>
      <Route path="/" render={() => <Home />} />
      <Route path="/about" component={About} />
    </Router>
  );
}

function Home() {
  return <>home</>;
}

function About() {
  return <>about</>;
}

Vale la pena señalar que potencialmente puedes eliminar el reder o la propiedad component por completo y usar el componente que desea asociar con una ruta determinada como hijo de Route:

import { BrowserRouter as Router, Route } from "react-router-dom";

export default function App() {
  return (
    <Router>
      <Route path="/about">
        <About />
      </Route>
    </Router>
  );
}

Finalmente, si deseas que un componente (como una barra de navegación) sea visible en todas las páginas, colóquelo dentro del BrowseRouter, pero arriba (o debajo) de las rutas declaradas:

import { BrowserRouter as Router, Route } from "react-router-dom";

export default function App() {
  return (
    <Router>
      <Navbar />
      <Route path="/" component={Home} />
      <Route path="/about" component={About} />
    </Router>
  );
}

function Navbar() {
  // visible on every page
  return <>navbar</>
}

function Home() {
  return <>home</>;
}

function About() {
  return <>about</>;
}

Componente switch

Cuando comencemos a agregar múltiples rutas, notaremos algo extraño.

Digamos que tenemos una ruta para la página de inicio y la página acerca de. Aunque especificamos dos rutas diferentes, '/' y '/about', cuando visito la página acerca de, veremos los componentes de inicio y acerca de.

Podemos arreglar esto con la propiedad exact, en la ruta de inicio para asegurarnos de que nuestro enrutador coincida exactamente con la ruta '/' en lugar de '/about':

import { BrowserRouter as Router, Switch, Route } from "react-router-dom";

export default function App() {
  return (
    <Router>
      <Navbar />
      <Switch>
        <Route exact path="/" component={Home} />
        <Route path="/about" component={About} />
      </Switch>
    </Router>
  );
}

Cuando se trata de cambiar entre diferentes rutas que nuestro enrutador debería mostrar, de hecho hay un componente dedicado que debe usar si tiene múltiples rutas dentro de su enrutador y ese es el componente Switch.

El componente switch debe incluirse dentro del componente Router y podemos colocar todas nuestras rutas dentro de él:

import { BrowserRouter as Router, Switch, Route } from "react-router-dom";

export default function App() {
  return (
    <Router>
      <Navbar />
      <Switch>
        <Route exact path="/" component={Home} />
        <Route path="/about" component={About} />
      </Switch>
    </Router>
  );
}

El componente switch examina todas sus rutas secundarias y muestra la primera cuya ruta coincide con la URL actual.

Este componente es el que queremos usar en la mayoría de los casos para la mayoría de las aplicaciones, porque tenemos múltiples rutas y múltiples páginas en nuestra aplicación, pero solo queremos mostrar una página a la vez.

Si por alguna razón deseas que se muestren varias páginas al mismo tiempo, puedes considerar no usar el componente switch.

Ruta 404

Si intentamos ir a una ruta que no existe en nuestra aplicación, ¿qué vamos a ver?

No vamos a ver nada si no tenemos una ruta correspondiente. ¿Cómo hacemos una ruta global?

Si un usuario intenta ir a una página para la que no tenemos una ruta definida, podemos crear una ruta y luego establecer la ruta con un asterisco *:

import { BrowserRouter as Router, Switch, Route } from "react-router-dom";

export default function App() {
  return (
    <Router>
      <Navbar />
      <Switch>
        <Route path="/" component={Home} />
        <Route path="/about" component={About} />
        <Route path="*" component={NotFound} />
      </Switch>
    </Router>
  );
}

function NotFound() {
  return <>Ha llegado a una página que no existe</>;
}

Esto coincidirá con cualquier intento de visitar una página que no existe y podemos conectarlo a un componente no encontrado para decirles a nuestros usuarios que han "Llegado a una página que no existe".

Digamos que dentro de nuestra barra de navegación, en realidad queremos crear algunos enlaces para poder movernos por nuestra aplicación más fácilmente en lugar de tener que cambiar la URL manualmente en el navegador.

Podemos hacerlo con otro componente especial de React Router DOM llamado componente Link. Acepta la propiedad to, que especifica a dónde queremos que el enlace navegue nuestro usuario. En nuestro caso, podríamos tener un enlace de inicio y acerca de:

import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";

export default function App() {
  return (
    <Router>
      <Navbar />
      <Switch>
        <Route path="/" component={Home} />
        <Route path="/about" component={About} />
      </Switch>
    </Router>
  );
}

function Navbar() {
  return (
    <nav>
      <Link to="/">Home</Link>
      <Link to="/about">About</Link>
    </nav>
  )
}

El componente Link nos permite proporcionar algunos estilos en línea como cualquier componente estándar de React. También nos brinda una propiedad útil para el componente, por lo que podemos configurar nuestro enlace como nuestro propio componente personalizado para un estilo aún más fácil.

Además, React Router DOM nos proporciona el componente NavLink que es útil en caso de que queramos aplicar algunos estilos especiales.

Si estamos en la ruta actual a la que apunta el enlace, esto nos permite crear algunos estilos de enlaces activos para decirles a nuestros usuarios, al mirar nuestro enlace, en qué página se encuentran.

Por ejemplo, si nuestros usuarios están en la página de inicio, podríamos decirles lo mismo usando el accesorio activeStyle para hacer que nuestro enlace esté en negrita y rojo cuando estén en la página de inicio:

import {
  BrowserRouter as Router,
  Switch,
  Route,
  NavLink
} from "react-router-dom";

export default function App() {
  return (
    <Router>
      <Navbar />
      <Switch>
        <Route path="/" component={Home} />
        <Route path="/about" component={About} />
      </Switch>
    </Router>
  );
}

function Navbar() {
  return (
    <nav>
      <NavLink
        activeStyle={{
          fontWeight: "bold",
          color: "red"
        }}
        to="/"
      >
        Home
      </NavLink>
      <NavLink activeClassName="active" to="/about">
        About
      </NavLink>
    </nav>
  );
}

También hay una propiedad activeClassName que también se puede configurar si no deseas incluir estilos en línea o deseas más estilos reutilizables para realizar la misma función que activeStyle.

Componente Redirect

Otro componente muy útil que nos da React Router DOM es el componente de redireccionamiento.

Puede parecer extraño tener un componente que realice la función de redirigir a nuestro usuario cuando se muestra, pero esto es muy funcional.

Siempre que usemos algo como una ruta privada y tengamos una condición en la que el usuario no esté autenticado, queremos redirigirlo a la página de inicio de sesión.

A continuación, se muestra un ejemplo de una implementación de un componente de ruta privada que garantiza que un usuario esté autenticado antes de mostrarle una ruta en particular que ha sido declarada con este componente.

De lo contrario, si no están autenticados, serán redirigidos a una ruta pública (presumiblemente una ruta para iniciar sesión) una vez que se muestre el componente de redireccionamiento:

import {
  BrowserRouter as Router,
  Switch,
  Route,
  Redirect
} from "react-router-dom";

export default function App() {
  return (
    <Router>
      <Switch>
        <Route exact path="/" component={Home} />
        <PrivateRoute path="/hidden" component={Hidden} />
      </Switch>
    </Router>
  );
}

function PrivateRoute({ component: Component, ...rest }) {
  // useAuth es un hook personalizado para obtener el estado de autenticación del usuario actual
  const isAuth = useAuth();

  return (
    <Route
      {...rest}
      render={(props) =>
        isAuth ? <Component {...props} /> : <Redirect to="/" />
      }
    />
  );
}

function Home() {
  return <>home</>;
}

function Hidden() {
  return <>hidden</>;
}

El componente Redirect es muy simple de usar, muy declarativo y nos permite ver el gran beneficio de que React Router DOM esté basado en componentes, como todo en React.

Hook useHistory

Además de todos estos poderosos componentes, hay algunos hooks muy útiles que React Router DOM nos brinda.

Son útiles principalmente al proporcionar información adicional que podemos utilizar dentro de nuestros componentes. Se pueden llamar como hooks de React normales para los que podemos usar sus valores exactamente como queramos.

Perhaps the most powerful hook is the useHistory hook. We can call it up at the top of any component that is declared within our router component and get back history data, which includes information such as the location associated with our component. Quizás el hook más poderoso es el hook useHistory. Podemos llamarlo en la parte superior de cualquier componente que se declare dentro de nuestro componente de Router y recuperar los datos de history, que incluyen información como la ubicación asociada con nuestro componente.

Este nos dice todo acerca de dónde se encuentra actualmente el usuario, como el nombre de la ruta en la que se encuentra, así como cualquier parámetro de consulta que pueda agregarse a nuestra URL. Se puede acceder a todos los datos de ubicación desde history.location:

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


function About() {
  const history = useHistory();
    
  console.log(history.location.pathname); // '/about'

  return (
    <>
     <h1>La página about esta en: {history.location.pathname}</h1>
    </>
  );
}

Además, el objeto history incluye directamente métodos útiles que nos permiten dirigir mediante programación a nuestro usuario a diferentes páginas de nuestra aplicación.

Esto es muy útil, por ejemplo, para redirigir a nuestro usuario después de iniciar sesión, o en cualquier situación en la que necesitemos llevar a un usuario de una página a otra.

Podemos empujar a los usuarios de una página a otra usando history.push. Cuando usamos el método push, solo necesitamos proporcionar la ruta que queremos llevar a nuestros usuarios a usar este método. Agrega esta nueva página a la pila (por así decirlo) de nuestro history:

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


function About() {
  const history = useHistory();
    
  console.log(history.location.pathname); // '/about'

  return (
    <>
     <h1>The about page is on: {history.location.pathname}</h1>
     <button onClick={() => history.push('/')}>Go to home page</button>
    </>
  );
}

También podemos redirigir a nuestros usuarios con history.replace, que también acepta un valor de ruta, pero borra todo en el historial, después de que se realiza la navegación. Esto es útil para situaciones en las que ya no es necesario retroceder en el historial, como después de que los usuarios hayan cerrado la sesión.

Hook useLocation

El hook useLocation incluye toda la misma información que el hook useHistory.

Es importante tener en cuenta que si necesita tantos datos de ubicación cómo usar el historial para navegar programáticamente por su usuario, asegúrese de usar useHistory. Sin embargo, si solo desea datos de ubicación, todo lo que necesita hacer es llamar a useLocation o recuperar todos los datos de ubicación en un objeto que sea idéntico a los datos proporcionados en el history.location:

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


function About() {
  const location = useLocation();
    
  console.log(location.pathname); // '/about'

  return (
    <>
     <h1>La página about esta en: {location.pathname}</h1>
    </>
  );
}

Hook useParams  + Rutas dinámicas

Una cosa que no cubrimos cuando se trata de rutas es que naturalmente podemos crear rutas dinámicas. Esto significa rutas que no son fijas y determinadas, pero que pueden tener cualquier número de caracteres.

Las rutas dinámicas son útiles en situaciones en las que tenemos, digamos, una publicación de blog con un slug o identificador único. ¿Cómo nos aseguramos de mostrar los datos adecuados y los componentes adecuados, dado que el slug de nuestra publicación en el blog puede ser completamente diferente?

Para declarar un parámetro de ruta en una ruta determinada, este debe ir precedido de dos puntos :. Si queremos crear una ruta dinámica, "/ blog /: postSlug", para un componente de publicación de blog, podría verse así:

import React from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";

export default function App() {
  return (
    <Router>
      <Switch>
        <Route exact path="/" component={Home} />
        <Route path="/blog/:postSlug" component={BlogPost} />
      </Switch>
    </Router>
  );
}

function Home() {
  return <>home</>;
}

function BlogPost() {
  return <>blog post</>;
}

Ahora estamos haciendo coincidir el componente apropiado o lo que sea el slug o identificador único. Pero dentro de nuestro componente BlogPost, ¿cómo recibimos los datos de esa publicación?

Podemos acceder a cualquier parámetro de ruta de una ruta declarada con su componente asociado usando el hook useParams.

useParams devolverá un objeto que contendrá propiedades que coincidan con nuestros parámetros de ruta (en este caso, postSlug). Podemos usar la desestructuración de objetos para acceder inmediatamente y declarar como una variable con el nombre postSlug:

import React from "react";
import { BrowserRouter as Router, Switch, Route, useParams } from "react-router-dom";

export default function App() {
  return (
    <Router>
      <Switch>
        <Route exact path="/" component={Home} />
        <Route path="/blog/:postSlug" component={BlogPost} />
      </Switch>
    </Router>
  );
}

function Home() {
  return <>home</>;
}

function BlogPost() {
  const [post, setPost] = React.useState(null);
  const { postSlug } = useParams();

  React.useEffect(() => {
    fetch(`https://jsonplaceholder.typicode.com/posts/${postSlug}`)
      .then((res) => res.json())
      .then((data) => setPost(data));
  }, [postSlug]);

  if (!post) return null;

  return (
    <>
      <h1>{post.title}</h1>
      <p>{post.description}</p>
    </>
  );
}

Si vamos a la ruta '/blog/my-blog-post', puedo acceder a la cadena 'my-blog-post' en la variable postSlug y recuperar los datos asociados a esa publicación dentro de useEffect.

useRouteMatch Hook

Si queremos saber si el componente dado está en una página determinada, podemos usar el hook useRouteMatch.

Por ejemplo, dentro de nuestra publicación de blog, para ver si la página en la que estamos coincide con la ruta "/blog/:postSlug", podemos recuperar un valor booleano que nos dirá si la ruta en la que estamos coincide con el patrón que especificamos:

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

function BlogPost() {
  const isBlogPostRoute = useRouteMatch("/blog/:postSlug");
 
  // mostrar, ocultar contenido o hacer otra cosa
}

Esto es útil en condiciones en las que queremos mostrar algo específico, en función de si estamos en una ruta determinada o no.

¿Quiere conservar esta guía para futuras consultas?

Haz clic aquí para descargar la hoja de referencia en formato PDF

Aquí hay 3 ganancias rápidas que obtiene cuando obtiene la versión descargable:

  • Obtendrás toneladas de fragmentos de código copiables para reutilizarlos fácilmente en sus propios proyectos.
  • Es una excelente guía de referencia para fortalecer sus habilidades como desarrollador de React y para entrevistas de trabajo.
  • Puede tomar, usar, imprimir, leer y releer esta guía literalmente en cualquier lugar que desees.

Traducido del artículo de Reed Barger - The React Router Cheatsheet – Everything You Need to Know