4.8 React router

Last updated 8 months ago

Contenidos

Introducción

En esta sesión veremos cómo usar React para escribir aplicaciones web de una sola página (Single Page Applications, en inglés) usando un complemento llamado React Router.

¿Para qué sirve lo que vamos a ver en esta sesión?

Una de las características fundamentales de la Web es el enlace, link o URL (siglas en inglés de "localizador de recursos uniforme"). Los enlaces permiten relacionar páginas entre sí, que unas nos lleven a otras, pero quizá una de las cosas más importantes es que se pueden compartir para que otras personas accedan al mismo contenido que nosotros.

Cuando se habla de SPAs se hace referencia a un tipo de web que consta exclusivamente de una página: un solo archivo HTML, con archivos CSS y JavaScript. Toda la interacción transcurre dentro de esa página, manejada con JavaScript, que imita a una ventana de las aplicaciones de escritorio. Por eso muchas veces hablamos de aplicaciones web cuando nos referimos a SPAs. Sin embargo, en esta transformación de web a aplicación web se perdería la esencia más útil de la Web si no se conservase un sistema de enlaces que diferencie las diferentes páginas que componen la aplicación.

Para reconciliar esta situación aparecieron técnicas de routing en JavaScript (en el lado del cliente) que manipulan intensivamente los hashes (#) de las URL y respetan la History API. Es decir, "simulan" distintas direcciones URL en el navegador, lo que se llaman rutas, de forma que el usuario puede usar los botones de "página anterior" y "página siguiente" del navegador para desplazarse por distintas pantallas de la aplicación web, y permiten compartir enlaces que lleven específicamente a una pantalla, aunque en realidad todo esté hecho en una sola página (SPA).

Qué es React Router

React Router es una librería compatible con React (aunque no desarrollada por el equipo de React) que nos permite especificar rutas en nuestra aplicación web usando componentes de React. Es decir, con otras librerías especificaríamos las rutas por código JavaScript, pero con React Router las escribiremos en componentes de React como <Route path='/about'>.

React Router se aprovecha de la separación de la interfaz en componentes que hace React. La lógica básica de cómo funciona es simple: depende de la ruta de la página en la que estemos, se pinta un componente u otro. Por ejemplo, podríamos decirle que si estamos en la ruta / renderice el componente <Home /> en la página, pero si estamos en la ruta /about, que renderice el componente <About />.

Una de las características de las SPAs es que también mantienen el estado entre pantallas de nuestra página. Con React Router y la arquitectura de componentes con estado que vimos en la sesión 4.6 esto se puede observar en el estado de nuestro componente principal, que normalmente se llamará algo parecido a <App />. <App /> tiene el estado relativo a todos los componentes incluídos dentro de sí, y aunque cambiemos un componente dentro de él dependiendo de la ruta, seguimos conservando los datos del estado que tenemos en <App />.

Uso básico del router para navegar entre pantallas de nuestra SPA

Para empezar a usar React Router, en nuestro proyecto generado con create-react-app debemos instalar y guardar la dependencia de npm de la siguiente manera:

npm install --save react-router-dom

Para activar el enrutado en nuestra aplicación, haremos lo siguiente. En nuestro archivo index.js importaremos el componente HashRouter, y renderizaremos nuestro componente principal <App /> dentro, como children:

index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import { HashRouter } from `react-router-dom`;
// ...
ReactDOM.render(
<HashRouter>
<App />
</HashRouter>,
document.getElementById('react-root')
);

En nuestro componente App.js ahora ya podemos declarar las rutas. Importaremos Route y Switch. El componente Switch incluirá dentro tantos componentes Route como rutas queramos en nuestra web y se asegurará de que solo se pinte uno. Dentro de cada componente Switch el contenido variará dependiendo de la ruta de la aplicación. A cada componente Route le pasaremos por props la clase del componente que queremos que se renderize:

App.js:

import React from 'react';
import { Route, Switch } from 'react-router-dom';
class App extends React.Component {
// ...
render() {
return (
<div>
{/* ... */}
<main>
<Switch>
<Route exact path='/' component={ Home } />
<Route path='/about' component={ About } />
</Switch>
</main>
</div>
);
}
}
// ...

Una vez declaradas las rutas, ya podemos hacer enlaces a las distintas pantallas de nuestra aplicación web. Para esto usaremos el componente Link, también de React Router, que se encargará de convertir nuestras rutas en enlaces. Le pasaremos una prop de nombre to con nuestra ruta:

import React from 'react';
import { Link, Route, Switch } from 'react-router-dom';
class App extends React.Component {
// ...
render() {
return (
<div>
<header>
<nav>
<ul>
<li><Link to='/'>Home</Link></li>
<li><Link to='/about'>About</Link></li>
</ul>
</nav>
</header>
<main>
<Switch>
<Route exact path='/' component={ Home } />
<Route path='/about' component={ About } />
</Switch>
</main>
</div>
);
}
}
// ...

▸ Rutas con React Router en Codepen

EJERCICIO 1: Me gustan tus pestañas

Vamos a crear una web con 3 pestañas: 'home', 'pricing' y 'about'. Para eso, lo primero vamos a crear un nuevo proyecto con create-react-app.

Ahora, creamos 3 componentes, uno por cada pestaña con un contenido lorem y con el nombre de la pestaña.

Luego, en nuestro componente principal (App) vamos a dibujar las 3 pestañas (3 enlaces) con el nombre de cada una y ocupando el 100% del ancho de la ventana.

Finalmente instalamos React Router en nuestro proyecto, y conseguimos que al pinchar en una pestaña, se pinte debajo el componentne correspondiente. ¡A por ello!

BONUS: Gestión avanzada de rutas

Los componentes Route aceptan distintas props. En la sección anterior hemos visto la más básica, component. Cuando pasamos la prop así, el componente Route renderizará ese componente cuando la ruta coincida con la que especifica en path. Sin embargo, podemos querer renderizar algo más complejo, o puede que queramos pasar props a ese componente. Para esas situaciones, Route acepta una prop de nombre render al que le pasaremos una función que devuelva lo que queremos que se pinte.

// ...
class App extends React.Component {
// ...
render() {
return (
<div>
{/* ... */}
<main>
<Switch>
<Route exact path='/' component={ Home } />
<Route path='/about' render={ () => <About objective="showing how React Router works" /> } />
</Switch>
</main>
</div>
);
}
}
// ...

También podemos utilizar una tercera prop de nombre children disponible en Route. Será también una función que devuelve lo que queremos que se pinte, pero se pintará siempre, tanto si estamos en la ruta como si no. La gracia de esto es que la función acepta un objeto como parámetro que nos pasará el componente Route automáticamente y que incluye información sobre la ruta actual, con la que podremos modificar la salida. Por ejemplo, con la siguiente función podemos hacer fácilmente la lista de navegación de la página y que se destaque la página actual:

function renderLinkAndHightlightActive(route, text) {
return (
<Route
path={ route }
children={
({ match, history, location }) => {
const activeClass = (!!match && match.isExact)
? 'nav-link--active'
: 'nav-link--normal';
return (
<Link
to={ route }
className={ activeClass }
>{ text }</Link>
);
}
}
);
}

▸ Menú consciente de la ruta actual en Codepen

Recursos externos

Blog de Paul Sherman

Tutorial sencillo de React Router v4. Incluye más información sobre las distintas plataformas en las que React Router funciona y las diferencias con las versiones anteriores (en inglés).

Blog de Krasimir Tsonev

Explicación en profundidad de cómo funciona un router del lado del cliente con JavaScript (en inglés).

Documentación de React Router

Documentación oficial de React Router. Define la API y muestra ejemplos (en inglés).