React/ReactJS: Router
Navigation between pages is indespensible part of any web application. There are various ways to set up routing in ReactJS. In this tutorial, we pick react-router, a popular declarative component-based router.
Since v4, it has been sub-categorized into three packages: react-router, react-router-dom, and react-router-native. The first package, react-router, is the root package of them all; the other two are environment-specific (depends on whether you are creating a geneic website or a mobile app). If you are building a website, use react-router-dom, but if you are building a mobile app in React Native, use react-router-native.
For our purpose here, we choose react-router-dom.
Install the react-router-dom package.
npm install react-router-dom --save
<HashRouter/>
v/s <BrowserRouter/>
Now there are two router components to go about from here:
- <HashRouter/>
- <BrowserRouter/>
The difference between the two is mainly in the URLs they generate.
<HashRouter/> relies on hashes (window.location.hash) to sync UI with the URL. This component is suitable for static websites. AngularJS old timers will find it familiar.
//<HashRouter/>
http://localhost:3000/#/about
<BrowserRouter/> uses HTML5 history API to keep the component UI in sync with the URL. There are no hashes in the URL.
//<BrowserRouter/>
http://localhost:3000/about
For the purpose of our tutorial, we will choose <HashRouter/>.
Configuring Router
The configuration shown below is to be done in the index.js file.
Create two functional components <About/> and <Services/>, each returning a single <h1> element containing the texts "About" and "Services" respectively.
import React from 'react';
import ReactDOM from 'react-dom';
const About = () => {
return (
<h1>About</h1>
);
}
const Services = () => {
return (
<h1>Services</h1>
);
}
The goal is to load each of these components separately on click of some links configured to them specifically.
We next import HashRouter and Route from react-router-dom into index.js. Now instead of the usual App component, set up the HashRouter and Route components inside render() as follows.
import React from 'react';
import ReactDOM from 'react-dom';
import { HashRouter, Route } from 'react-router';
const About = () => {
return (
<h1>About</h1>
);
}
const Services = () => {
return (
<h1>Services</h1>
);
}
ReactDOM.render(
<HashRouter>
<div>
<Route path="/about" component={About}/>
<Route path="/services" component={Services}/>
</div>
</HashRouter>
, document.getElementById('root'));
NOTE: Notice the <div/> element child of <HashRouter>. That is because a router component can have only a single child element, and all the <Route/> elements are wrapped inside it.
Link
Next we import Link to provide accessible navigation, which actually is quite akin to the <a> tag. We construct one more functional component called <App/> to implement the Link component as shown below. Also note that we create a new route for it, with the path attribute set to /, which is the home/landing page.
import React from 'react';
import ReactDOM from 'react-dom';
import { HashRouter, Route, Link } from 'react-router-dom';
const About = () => {
return (
<h1>About</h1>
);
}
const Services = () => {
return (
<h1>Services</h1>
);
}
const App = () => {
return (
<div>
<ul>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/services">Services</Link>
</li>
</ul>
</div>
)
}
ReactDOM.render(
<HashRouter>
<div>
<Route path="/" component={App}/>
<Route path="/about" component={About}/>
<Route path="/services" component={Services}/>
</div>
</HashRouter>
, document.getElementById('root'));
It is a simple set-up without any styling. It gets rendered as below:
Now if you click on any of the link, About or Services, the respective components will load — but along with the component specified for the default / path. The loaded pages look as follows:
This actually is unwanted (and could have avoided had we used <BrowserRouter/> in place of <HashRouter/>). But there is an easy way out of it; we just have to add the exact props to the <Route/> component.
Adding the exact props
We add it to the first (default) component above.
<Route exact path="/" component={App}/>