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.

react router

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:

react router implementation

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:

reactjs router without ref

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}/>