Cómo crear una aplicación SPA usando React Router

React

En este tutorial aprenderás a usar React Router para crear una aplicación SPA «Single Page Application». React no incorpora un router por defecto que permita modificar dinámicamente las rutas del navegador, pero podemos obtener esta funcionalidad mediante la librería react-router-dom.

Introducción

En este tutorial aprenderás a crear una página SPA usando la librería react-router-dom, modificando tanto el contenido como la ruta del navegador dinámicamente. Crearemos una aplicación de ejemplo en la que obtendremos datos desde una API y los mostraremos por pantalla.

Sin embargo, existen ciertos conocimientos previos que deberías tener antes de continuar con este tutorial, ya que deberías tener conocimientos básicos de HTML, de CSS, de JavaScript y también deberías saber crear una aplicación usando React. Si no dispones de estos conocimientos, a continuación encontrarás varias guías y tutoriales que te servirán de ayuda:

Además, también es recomendable que sepas cómo conectarte a una API con JavaScript. Aunque no es impresindible, ya que las explicaremos brevemente, también es recomendable que hayas usado alguna vez las Hooks de React. Si tienes dudas, consulta el siguiente tutorial, en donde explico cómo crear una aplicación con React usando Hooks.

Puedes consultar el código de la aplicación que vamos a crear en GitHub.

Acerca de las rutas

Vamos a empezar explicando qué es un enrutador o router. Cuando accedes a una web, como podría ser el caso de esta, podrás comprobar que estás en la URL https://neoguias.com. Sin embargo, cuando accedes a la sección de tutoriales, se cargará una nueva página y la ruta que mostrará el navegador cambiará a https://neoguias.com/tutoriales.

Sin embargo, cuando creas una aplicación con React, la ruta será siempre la misma, ya que únicamente cambiará el contenido de la aplicación de forma dinámica, dentro de una misma página. Aquí es en donde entra en juego React Router.

Si por ejemplo accedes a la URL https://tutorialmarkdown.com, que es una aplicación creada con React, y luego accedes a alguna de sus secciones, como aquella en la que se explica qué es Markdown, verás que la URL pasa a ser https://tutorialmarkdown.com/markdown, sin haberse cargado una nueva página.

Lo que ocurre es que la librería react-router-dom se encarga de modificar dinámicamente la ruta del navegador cada vez que accedes a una nueva página. Por ejemplo, esta última página usa las siguientes rutas:

  • /: Ruta raíz de la web.
  • /:id_pagina: Ruta de cada una de las páginas de primer nivel de la web.
  • /aplicaciones/:id_aplicacion: Ruta de cada una de las aplicaciones listadas en la sección de aplicaciones de la web.

Una vez definidas las rutas, el enrutador se encarga de cargar la plantilla, los componentes y el contenido correspondiente. En la páginas SPA como esta última, solamente se carga una página y, con cada nuevo clic, se cargan ciertos componentes o ciertos datos JSON que modifican la vista de la página. Esto ocurre de forma transparente al usuario, sin que el navegador redirija la aplicación a un nuevo archivo o página.

Creación del proyecto

Para empezar, abre una ventana de línea de comandos y dirígete al directorio en el que quieres crear la aplicación. Luego usa la utilidad create-react-app para crear la aplicación:

npx create-react-app tutorial-react-router

La aplicación se creará en el directorio /tutorial-react-router, así que accede a él y luego usa uno de los siguientes comandos para instalar el paquete react-router-dom:

# Si usas npm
npm install react-router-dom

# Si usas Yarn
yarn add react-router-dom

Además, también usaremos la librería Axios para realizar peticiones asíncronas a la API, así que instala el paquete axios usando uno de estos dos comandos:

# Si usas npm
npm install axios

# Si usas Yarn
yarn add axios

Instala las dependencias de la aplicación con uno de estos dos comandos:

# Si usas npm
npm i

# Si usas Yarn
yarn install

Finalmente, usa uno de estos comandos para iniciar el servidor de desarrollo de la aplicación:

# Si usas npm
npm start

# Si usas Yarn
yarn start

En este tutorial no prestaremos demasiada atención a los estilos CSS, pero en caso de que quieras que se apliquen algunos estilos por defecto, puedes copiar el código de Bootstrap desde aquí y pegarlo en el archivo /src/index.css.

Configuración del router

Para usar react-router-dom tenemos que incluir toda la aplicación App en el interior del componente BrowserRouter o del componente HashRouter que podemos importar desde la propia librería react-router-dom. En función de esto, existen dos tipos de rutas que podemos configurar. Por un lado tenemos las rutas estándar del navegador y por otro las rutas hash:

  • Rutas del navegador: Son las rutas del componente BrowserRouter, que representan las típicas pretty URLs como la de esta ruta.de/ejemplo.
  • Rutas del hash: Son las rutas del componente HashRouter, que sencillamente agrega un símbolo sostenido # y el nombre de la ruta al final de la ruta actual, como en esta ruta.de/#ejemplo.

En nuestra aplicación vamos a usar las rutas BrowserRouter agregando este código al archivo index.js de la aplicación, que debes crear en caso de que todavía no lo hayas hecho:

import React from 'react';
import { render } from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import './index.css';

render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.querySelector('#root')
);

Creación de rutas

Ahora edita o crea el archivo App.js, en donde agregaremos las rutas del proyecto y los componentes a los que estarán asociadas. Las rutas las definimos mediante el componente Route, que nos permite establecer la ruta o path de las mismas y el componente asociado a cada una.

Las rutas las agruparemos en el interior de un bloque Switch, que cargará la ruta correspondiente a la URL actual según el orden de preferencia en el que están definidas.

Vamos a importar los componentes PaginaInicio y PaginaUsuario que todavía no hemos creado, cosa que haremos en el siguiente apartado. Luego vamos a definir dos rutas, una que se corresponderá con la raíz / y otra con /:nombre:

import React from 'react';
import { Route, Switch } from 'react-router-dom';

import PaginaInicio from './paginas/PaginaInicio';
import PaginaUsuario from './paginas/PaginaUsuario';

export default function App() {
  return (
    <Switch>
      <Route exact path="/" component={PaginaInicio} />
      <Route path="/:nombre" component={PaginaUsuario} />
    </Switch>
  );
}

Mediante el atributo path definimos la ruta y mediante el atributo component definimos el componente que se encargará de mostrar al usuario la página deseada.

En cuanto a la primera ruta, el atributo exact indica que la ruta tendrá que corresponderse exactamente con la indicada en el path. A diferencia de los enrutadores de otros frameworks como Laravel o SCIWP, React Router acepta coincidencias parciales. Es decir, que se definimos primero la ruta /usuarios y luego la ruta /usuarios/mostrar y accedemos a la URL /usuarios/mostrar, se cargará la ruta /usuarios a no ser que usemos el atributo exact en /usuarios.

En cuanto a la ruta /:nombre, los dos puntos indican que lo que viene después es una variable, que en este caso se corresponderá con el nombre de un usuario. De este modo podemos usar una misma plantilla con cualquier usuario.

Podríamos definir más tipos de rutas, aunque sale del alcance de este proyecto, creado con fines didácticos. Por ejemplo, podríamos agregar también las siguientes rutas:

<Switch>
  <Route exact path="/" component={PaginaInicio} />
  <Route path="/:nombre" component={PaginaUsuario} />
  <Route path="/categorias" component={PaginaCategorias} />
  <Route path="/categorias/:id" component={PaginaCategoria} />
</Switch>

En este ejemplo, la ruta /categorias nos llevaría a una página en la que mostraríamos un listado de categorías, mientras la ruta /categorias/:id nos llevaría a una página en la que se mostraría una categoría individual. Ejemplos de rutas que coincidirían con esta última ruta serían /categorias/php o /categorias/mysql.

Creación de enlaces

Cuando usas rutas, podrás crear enlaces hacia otras páginas de tu aplicación normalmente, como en el siguiente ejemplo:

<a title="Ruta de ejemplo" href="/ruta-ejemplo">

Sin embargo, el enlace anterior hará que la página se refresque, cargando así una nueva página sin aprovechar las ventajas de React. Por ello, React Router dispone del componente Link, que permite crear enlaces que carguen otras páginas dinámicamente.

Crea el componente PaginaInicio en el directorio /paginas y agrega este código, en donde simplemente agregamos un enlace a la página de un usuario:

import React from 'react';
import { Link } from 'react-router-dom';

export default function PaginaInicio() {
  return (
    <div className="container">
      <h1>Página de inicio</h1>
      <p>
        <Link to="/edulazaro">Proyectos de Edu</Link>
      </p>
    </div>
  );
}

Parámetros dinámicos

El enlace que hemos creado, que nos llevará a la página /edulazaro sin refrescar la página, entrando por la ruta /:nombre, que cargará el componente PaginaUsuario. En este componente podremos acceder a los parámetros especificados en la ruta mediante el objeto match.params, pasado al componente a través de sus  propiedades. Así, el nombre del usuario estaría en la propiedad props.match.params.nombre.

Vamos a crear el archivo PaginaUsuario creando un componente funcional que obtenga los datos del usuario especificado desde GitHub y los muestre por pantalla. En este caso, mostrará por pantalla los datos del usuario edulazaro.

Dado que se trata de un componente funcional, incluiremos el código que obtiene los datos desde la API en la función useEffect, que es una hook de React. La función useEffect se usa como alternativa al método componentDidMount de los componentes de clase de React. Si nunca has usado estas funciones, puedes consultar el tutorial en el que explico cómo crear una aplicación con React usando hooks.

Este es el código completo del componente PaginaUsuario, situado en el directorio /paginas:

import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import axios from 'axios';

export default function PaginaUsuario(props) {

  // Estado inicial del usuario
  const estadoInicial = {
    usuario: {},
    cargando: true,
  }

  // Permite obtener y modificar el estado
  const [usuario, setUsuario] = useState(estadoInicial);

  // Obtenemos datos desde la API de GitHub
  useEffect(() => {
    const getUsuario = async () => {
      
      // pasamos el nombre del usuario a la petición
      const ruta = `https://api.github.com/users/${props.match.params.nombre}`;
      const { data } = await axios(ruta);
      
      // Actualización del estado
      setUsuario(data)
    }

    // Ejecutamos la función
    getUsuario();
  }, []);

  // Mostramos por pantalla los dato
  return usuario.cargando ? (
    <div>Cargando...</div>
  ) : (
    <div className="container">
      <h1>{props.match.params.id}</h1>
      <table>
        <thead>
          <tr>
            <th>Nombre</th>
            <th>Localización</th>
            <th>Web</th>
            <th>Seguidores</th>
            
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>{usuario.name}</td>
            <td>{usuario.location}</td>
            <td><a href={usuario.blog}>{usuario.blog}</a></td>
            <td>{usuario.followers}</td>
          </tr>
        </tbody>
      </table>
      <Link to="/">Volver</Link>
    </div>
  )
}

Tal y como ves, hemos realizado una petición asíncrona usando await, esperando así a obtener un resultado de vuelta antes de continuar. Si quieres saber más cosas acerca del uso de async/await, consulta el siguiente tutorial, en donde explico el cómo usar funciones asíncronas con async/await en JavaScript.

También hemos agregado un enlace de regreso a la página principal después de la tabla.

Finalizando

Esto ha sido todo.. Puedes ver el proyecto en funcionamiento aquí o consultar el código del proyecto en GitHub.


Avatar de Edu Lazaro

Edu Lázaro: Ingeniero técnico en informática, actualmente trabajo como desarrollador web y programador de videojuegos.

👋 Hola! Soy Edu, me encanta crear cosas y he redactado esta guía. Si te ha resultado útil, el mayor favor que me podrías hacer es el de compatirla en Twitter 😊

Si quieres conocer mis proyectos, sígueme en Twitter.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

“- Hey, Doc. No tenemos suficiente carretera para ir a 140/h km. - ¿Carretera? A donde vamos, no necesitaremos carreteras.”