En React.js existe un librería llamada React Router que nos permite añadir rutas a cualquier proyecto React. En esta entrada, lo que vamos a hacer va a ser crear una navegación por rutas. Crearemos un componente por cada ruta para que se muestre uno u otro según la ruta en la que estemos. También, veremos cómo pasar parámetros a las rutas y cómo gestionar el acceso a una página no existente (404).
Instalar React Router
Instalamos la librería mencionada anteriormente:
1 |
npm install react-router-dom --save |
Crear rutas
Una vez finalice, vamos a cambiar un poco la estructura del proyecto. Creamos un directorio pages en src. Aquí pondremos todos los componentes que seán páginas. De momento, vamos a crear 3 que serán Home.js (que será el listado de posts), About.js (que sería un texto de sobre mí) y Contact.js (que sería un formulario de contacto).
pages/Home.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import React from "react"; import PostList from "../components/PostList"; class Home extends React.Component { render() { return ( <div> <h1>Blog</h1> <PostList /> </div> ); } } export default Home; |
pages/About.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import React from "react"; class About extends React.Component { render() { return ( <div> <h1>About me</h1> <div>Text...</div> </div> ); } } export default About; |
pages/Contact.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import React from "react"; class Contact extends React.Component { render() { return ( <div> <h1>Contact</h1> <div>Form...</div> </div> ); } } export default Contact; |
Cuando tengamos esto, vamos a ir a crear el enrutador. Para ello vamos al App.js y lo modificamos para que quede así:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import React, { Component } from "react"; import { BrowserRouter as Router, Route, Switch } from "react-router-dom"; import "./styles.css"; import Header from "./components/Header"; import Footer from "./components/Footer"; import Home from "./pages/Home"; import About from "./pages/About"; import Contact from "./pages/Contact"; class App extends Component { render() { return ( <Router> <div> <Header /> <Switch> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/contact" component={Contact} /> </Switch> <Footer /> </div> </Router> ); } } export default App; |
Como puedes ver, hemos quitado el componente <PostList /> porque ya está en la página Home.js. Estamos importando los componentes necesarios para crear el enrutador (router) de la librería react-router-dom y las utilizamos en el método render.
Utilizamos el componente BrowserRouter que es un enrutador que utiliza la API de history de HTML5 para mantener sincronizada la UI con la ruta que toque.
Después, estamos utilizando el componente Switch que es para que solamente renderice el primer componente que coincida con la ruta. Si no utilizásemos, Switch, nos renderizaría todos los componentes Route que coincidieran con la ruta a la que estamos accediendo.
Y finalmente utilizamos el componente Route que es el componente que define las rutas ( path) y el componente que debe renderizar ( component).
Ahora, debemos modificar el Header.js para que el menú de navegación seán enlaces a las rutas creadas. Abrimos el archivo y debería quedar así:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import React from "react"; import { Link } from "react-router-dom"; // class component class Header extends React.Component { render() { return ( <header> <div>Logo</div> <nav className="nav"> <Link to="/">Home</Link> <Link to="/about">About</Link> <Link to="/contact">Contact</Link> </nav> </header> ); } } export default Header; |
Importamos el componente Link de la librería y lo utilizamos para crear los links a las rutas creadas anteriormente.
Si quisieramos añadir una clase CSS para cambiar el estilo del enlace (poner en negrita, subrayado, etc.) que coincida con la ruta dónde estemos, deberemos utilizar el componente NavLink en vez de Link. Más información aquí.
Con todo esto, ya deberíamos tener una navegación por rutas creada con React Router en nuestra aplicación con React.js:
Crear rutas con parámetros
Ya hemos visto como crear rutas estáticas (sin parámetros), ahora vamos a ver cómo crear rutas con parámetros. Vamos a aprovechar el listado de posts y vamos a crear una ruta que acceda al detalle del post, es decir, que solamente aparezca el post que tenga el id que le pasemos por parámetro.
Creamos la página Post.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
import React from "react"; import PostItem from "../components/PostItem"; class Post extends React.Component { state = { post: null }; componentDidMount() { let postId = this.props.match.params.id; fetch(`https://jsonplaceholder.typicode.com/posts/${postId}`) .then(response => response.json()) .then(post => this.setState({ post })); } render() { if (this.state.post) { return ( <div> <PostItem post={this.state.post} /> </div> ); } else { return <p>Loading...</p>; } } } export default Post; |
Obtenemos el id pasado por parámetro con this.props.match.params.id y se lo pasamos a la API que vimos en anteriores posts, asignamos lo que devuelve la API a una variable del estado (state) llamada post y le pasamos al componente PostItem el post por las propiedades.
Ahora vamos al componente PostItem y lo modificamos para que quede así:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
... import { Link } from "react-router-dom"; class PostItem extends React.Component { ... render() { ... return ( <div> <h1> <Link to={`/post/${this.props.post.id}`}> {this.props.post.title} </Link> </h1> ... {this.props.onDelete && <button onClick={this.onDelete}>Delete</button>} </div> ); } } ... export default PostItem; |
Le añadimos el enlace para poder acceder a la ruta creada pasándole por parámetro el id del post.
Hecho todo esto, deberíamos ver algo así:
Gestionar el acceso a una página no existente (404)
Con React Router también podemos gestionar el acceso a una página no existente y que nos muestre una página tipo «Not found» o algo así. Para ello, creamos un archivo en src/pages/NotFound.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import React from "react"; class NotFound extends React.Component { render() { return ( <div> <p>Not Found</p> </div> ); } } export default NotFound; |
Ahora, vamos al App.js y añadimos al final del listado de rutas la siguientes líneas:
1 2 3 |
import NotFound from "./pages/NotFound"; ... <Route component={NotFound} /> |
Si entramos en una ruta que no existe en nuestro listado de rutas, nos aparecerá el mensaje que hayamos puesto en el componente NotFound.js.
Código completo de la entrada: https://github.com/fullstackseriescom/aprende-reactjs/tree/master/08-react-router
Ejemplo en vivo de la entrada: https://repl.it/@vreaxe/Reactjs-React-Router
-
Al colocar mi link en un … to»/contact», me hace el cambio en la URL, pero no me carga el componente. en el contenido.
en cambio al ponerlo fuera del si me carga los componentes, ¿a que se debe?
Que tengas un buen dia!
cuento con:
// lo carga perfecto, fuera del componente de MDB
{
items && items.map(
(item,key) => {item.title} )}
//con mi routes correspondientes
render(){
const {items} = this.props;
*Solucionado, es porque se contaba con etiqueta en el Navbar.
hasta cuantas rutas puedo ingresar debido que en mi proyecto tendré muchas rutas y quisiera saber como puedo aquello hacerlo modular.
Hola Samuel!
Muchas gracias por tu comentario.
Lo que puedes hacer es separar las rutas por ficheros. En este link explica cómo hacerlo: http://randycoulman.com/blog/2016/02/02/composing-routes-in-react-router/.
Espero que te sea de ayuda.