I’m consider a back-end developer but I like to step outside from my confort zone and for this reason I’ve decided to learn about front-end technologies. I’ve created a repository in Github where I’m trying to create a front-end app using React Hooks with an Azure Functions back-end. Step by step I hope to complete it using different approaches and best practices, and today I have to learn about routing in React in order to manage navigation, so I’ve decided to write a post for my future self.
In a React application we have an excellent solution to manage routing: React router-library.
We are going to create a new React application using React-cli:
npx create-react-app react-router-example
First, we need to install React-router with the command:
npm install react-router-dom --save
In the App.js file, add the code below (only for demo purpose because in a real application we should split the components in separated files):
import React from 'react';
import {
BrowserRouter as Router,
Switch, Route, Link
} from "react-router-dom"
const Home = () => {
return (
<div><h1>Home</h1></div>
)
}
const About = () => {
return (
<div><h1>About</h1></div>
)
}
const Contact = () => {
return (
<div><h1>Contact</h1></div>
)
}
const App = () => {
const styles = { padding: 5 }
return (
<Router>
<div>
<Link style={styles} to="/">Home</Link>
<Link style={styles} to="/about">About</Link>
<Link style={styles} to="/contact">Contact</Link>
</div>
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/contact">
<Contact />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
);
}
export default App;
Then, execute this command in order to test the example:
yarn start
Our example has 3 “pages” handled by the Router component, event though the component is referred by the name Route but in fact we are talking about BrowserRouter but we are using Named Imports, a new way to import modules provides by ES6.
import {
BrowserRouter as Router,
Switch, Route, Link
} from "react-router-dom"
We can find the definition of the BrowserRoute in this link
BrowserRoute uses the HTML5 history API (pushState, replaceState and the popstate event) to keep your UI in sync with the URL.
This component with the help of the HTML5 history API enable us to use the url in the address browser bar for internal routing in our React application without a full navigation like traditional web apps.
Inside the Router we can define links. We can use Link component that will modify the address bar in the browser:
<Link style={styles} to="/about">About</Link>
In this case, when user clicks on the link, the browser bar address will change to /about
We define our routes with the Route component, for example:
<Route path="/about">
<About />
</Route>
In this case, if the browser bar address match with /about the About component will be render.
We have to define as many Route components as we want inside the Switch component:
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/contact">
<Contact />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
The Switch works rendering the first component that match the browser address bar with the path property.
Another importan thing is the order of the Route components. If we change our example:
<Switch>
<Route path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/contact">
<Contact />
</Route>
</Switch>
The Home component will always be render and nothing more wourl ever get rendered:
URL parameters
Some times we will need a component that shows to the user a detail of some entity, product details, user profile, etc. With React router we have the ability to define parametrized urls. Let’s see an example:
import React from 'react';
import {
BrowserRouter as Router,
Switch, Route, Link,
useParams
} from "react-router-dom"
const products = [
{
id: 1,
name: 'Foo'
},
{
id: 2,
name: 'Bar'
}
]
const Home = () => {
return (
<div><h1>Home</h1></div>
)
}
const About = () => {
return (
<div><h1>About</h1></div>
)
}
const Contact = () => {
return (
<div><h1>Contact</h1></div>
)
}
const Product = ({ product }) => {
return (
<li>
<Link to={`/product/${product.id}`}>{product.name}</Link>
</li>
)
}
const ProductDetails = ({products}) => {
const id = useParams().id
const product = products.find(product => product.id === Number(id))
return (
<h3>Product: {product.name} details.</h3>
)
}
const App = () => {
const styles = { padding: 5 }
return (
<Router>
<div>
<Link style={styles} to="/">Home</Link>
<Link style={styles} to="/about">About</Link>
<Link style={styles} to="/contact">Contact</Link>
<ul>
{products.map(product =>
<Product
key={product.id}
product={product} />
)}
</ul>
</div>
<Switch>
<Route path="/product/:id">
<ProductDetails products={products} />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/contact">
<Contact />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
);
}
export default App;
We have created a new component in order to show a list of products.
const Product = ({ product }) => {
return (
<li>
<Link to={`/product/${product.id}`}>{product.name}</Link>
</li>
)
}
Clicking the name of the product Foo will trigger an event that change the browser bar address to product/1. We have created a new route inside the Switch component that looks like:
<Route path="/product/:id">
<ProductDetails products={products} />
</Route>
A new component called ProductDetails will be rendered passing all the products, but how can we retrieve the id passed in the url and filter the products by id? We access to the url parameters using useParams hook:
import {
...
useParams
} from "react-router-dom"
In the product details component we can use this hook:
const ProductDetails = ({products}) => {
const id = useParams().id
const product = products.find(product => product.id === Number(id))
return (
<h3>Product: {product.name} details.</h3>
)
}
Conclusion
In this post I’ve tried to show how straightforward is to added routes in our React applications with React router library.
Comments