Learning React by Practice – React Router for Beginners

Learning React by Practice - React Router for Beginners

Table of Contents

Imagine you could change the content of the website or app without reloading it. Impossible? Not at all. You can do that with something called React Router. How? I’m glad you are asking. Today, I will take you through all steps necessary to get React Router up and running. From now, you will see reloading the page as a history. Are you ready to explore what is possible with React Router?

Live demo on CodePen.

Briefing

Let’s start this React Router tutorial with quick briefing. There are two questions we need to answer. First, what are we going to build? Second, what will we need to get the job done? Let’s start with the first question. We are going to build very simple website with multiple pages. And, we will use React Router to wire these pages together. In other words, you will be able to browse the website without reloading the page. Sounds cool?

Now, let’s answer the second question. We will need a number of external assets. Some of these assets are necessary and some are optional. I built the demo on Bootstrap 4 (alpha 6). This means that one of the optional assets is Bootstrap 4. And yes, we will need both, CSS and JavaScript because we will be using Bootstrap’s mobile toggleable navigation. However, if you don’t want to use it, feel free to skip this. Another optional asset is jQuery.

Bootstrap requires jQuery library to run its scripts. So, if we want to use mobile navigation, or Bootstrap, you can skip this. I used slim version of jQuery. These were the optional assets. The necessary ones are React, ReactDOM and React Router. In addition to these assets, I also used Babel compiler. Babel allows us to use the latest JavaScript syntax without sacrificing browser compatibility.

The last thing I should mention is version of each asset. I already experienced some issues with using different versions of assets, especially React Router. So, we will be using React and ReactDOM version 15.4.2. The version of React Router is 4.0.0-alpha.6. Version of Bootstrap is 4.0.0-alpha.6 as well (coincidence). Version of jQuery is 3.1.1 (Slim).

Note: we are using the latest versions of all assets (to this date – 16. January 2017).

HTML

When it comes to HTML, we need to do only one thing. We need to create container where we will render the React app later. So, let’s create one div element with class “appRoot”. With this, we can move to CSS (Sass).

HTML:

<div class="appRoot"></div>

CSS (Sass)

One benefit of using some front-end framework, such as Bootstrap, is that it does a lot of styling for us. As a result, we will need to create smaller amount of custom styles to make this React Router tutorial up and running. First, we will change the background of body to picture. Because this picture is dark, we will need to change the color of text to white (#fff). To add contrast and make the text more visible, we will use :after pseudo-element to create dark overlay.

Next, we will use set of media queries to use different sizes of background image for different resolutions, starting from the smallest. In other words, we will design the website following mobile-first approach. We also need to increase the z-index of the container that contains the text. Otherwise, it would be covered by the overlay.

Sass:

body {
 position: relative;
 color: #fff;
 background-image: url(https://source.unsplash.com/II2ulqB-118/480x320);
 background-repeat: no-repeat;
 background-position: top center;
 background-size: cover;
 
 // Creating dark overlay for background image
 &:after {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  content: "";
  width: 100%;
  height: 100vh;
  background: rgba(0,0,0,.5);
 }
}

@media screen and (min-width: 480px) {
 body {
  background-image: url(https://source.unsplash.com/II2ulqB-118/768x1080);
 }
}

@media screen and (min-width: 768px) {
 body {
  background-image: url(https://source.unsplash.com/II2ulqB-118/992x1080);
 }
}

@media screen and (min-width: 992px) {
 body {
  background-image: url(https://source.unsplash.com/II2ulqB-118/1400x1080);
 }
}

// Avoid covering the text by overlay
body .container {
 z-index: 3;
}

Some more polishing

There will be a lot space. So, we can center the content horizontally and vertically. Well, except the gallery page. That could cause some issues. After that, we will set some default styling for h1 heading. We also need to set max-width of img elements to “100%”. Otherwise, they could overlap the its container and create a mess on gallery page. Then, we will restyle Bootstrap’s default navigation to fit our dark design. This includes adding custom styles for navigating links.

The last thing is add some more custom styles to gallery page. Images will be inside 3×3 grid and we should add some vertical spacing between the images. Bootstrap grid will take care about horizontal spacing. We can also add box-shadow to add some depth. Finally, we can add some styling for hover state, such as change of box-shadow.

Sass:

body:not(.page-gallery) .container {
 position: absolute;
 left: 0;
 top: 50%;
 right: 0;
 transform: translateY(-50%);
}

body:not(.page-gallery) .appRoot {
 position: relative;
 min-height: 320px;
 height: 100vh;
}

h1 {
 margin-top: 32px;
 margin-bottom: 32px;
 text-align: center;
 text-transform: uppercase;
}

img {
 max-width: 100%;
}

.nav {
 position: relative;
 z-index: 99;
}

.nav-link {
 font-weight: 700;
 color: #eee;
 transition: color .25s ease-out;
 
 &:focus,
 &:hover {
  color: #aaa;
 }
}

.nav-link-active,
.nav-link-active:focus {
 color: #fff;
 border-bottom: 2px solid;
}

// Add space above and below mobile nav
@media screen and (max-width: 768px) {
 .navbar-collapse {
  margin-top: 40px;
 }
 
 .navbar + div {
  margin-top: 40px;
 }
}

.page-gallery .col-4 {
 padding-top: 15px;
 padding-bottom: 15px;
}

.page-gallery img {
 box-shadow: 0 15px 35px rgba(50,50,93,.1),0 5px 15px rgba(0,0,0,.07);
 transition: box-shadow .25s ease-out;

 &:hover {
  box-shadow: 0 21px 35px rgba(50,50,93,.1),0 15px 15px rgba(0,0,0,.07);
 }
}

All in one piece

As always, let’s put all the bits and pieces of CSS (Sass) together.

Sass:

body {
 position: relative;
 color: #fff;
 background-image: url(https://source.unsplash.com/II2ulqB-118/480x320);
 background-repeat: no-repeat;
 background-position: top center;
 background-size: cover;
 
 // Creating dark overlay for background image
 &:after {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  content: "";
  width: 100%;
  height: 100vh;
  background: rgba(0,0,0,.5);
 }
}

@media screen and (min-width: 480px) {
 body {
  background-image: url(https://source.unsplash.com/II2ulqB-118/768x1080);
 }
}

@media screen and (min-width: 768px) {
 body {
  background-image: url(https://source.unsplash.com/II2ulqB-118/992x1080);
 }
}

@media screen and (min-width: 992px) {
 body {
  background-image: url(https://source.unsplash.com/II2ulqB-118/1400x1080);
 }
}

// Avoid covering the text by overlay
body .container {
 z-index: 3;
}

body:not(.page-gallery) .container {
 position: absolute;
 left: 0;
 top: 50%;
 right: 0;
 transform: translateY(-50%);
}

body:not(.page-gallery) .appRoot {
 position: relative;
 min-height: 320px;
 height: 100vh;
}

h1 {
 margin-top: 32px;
 margin-bottom: 32px;
 text-align: center;
 text-transform: uppercase;
}

img {
 max-width: 100%;
}

.nav {
 position: relative;
 z-index: 99;
}

.nav-link {
 font-weight: 700;
 color: #eee;
 transition: color .25s ease-out;
 
 &:focus,
 &:hover {
  color: #aaa;
 }
}

.nav-link-active,
.nav-link-active:focus {
 color: #fff;
 border-bottom: 2px solid;
}

// Add space above and below mobile nav
@media screen and (max-width: 768px) {
 .navbar-collapse {
  margin-top: 40px;
 }
 
 .navbar + div {
  margin-top: 40px;
 }
}

.page-gallery .col-4 {
 padding-top: 15px;
 padding-bottom: 15px;
}

.page-gallery img {
 box-shadow: 0 15px 35px rgba(50,50,93,.1),0 5px 15px rgba(0,0,0,.07);
 transition: box-shadow .25s ease-out;

 &:hover {
  box-shadow: 0 21px 35px rgba(50,50,93,.1),0 15px 15px rgba(0,0,0,.07);
 }
}

JavaScript (React)

We completed HTML and CSS (Sass). Now, we have to take care about the JavaScript. This is the most important part of this React Router tutorial. I added comments right into the code to those parts that are more complex. I hope this will make it easier for your to understand how React Route works and how to use it. Anyway, let’s begin. We will import necessary parts from React Router and store them inside variable. We can do the same with the HTML container.

JavaScript (React):

// // Store all components of React Router inside variable
const {
 Route,
 Router,
 Link,
 hashHistory,
 IndexRoute,
 IndexLink
} = ReactRouter;

// Store the container for rendering our website
const appRoot = document.querySelector('.appRoot');

Main component

Next, we will create our first component. This will be basically our default. This component will contain Navigation component. We will create this component later. It will also contain a block of code that will allow us render currently active route. Or, it will render the page we select as indexRoute. This will happen when we load the page.

JavaScript (React):

// Component for main component
class App extends React.Component {
 render() {
  return (
   <div>
    <Navigation />

    {/* Render active Route or indexRoute */}
    {this.props.children}
   </div>
  );
 }
}

Homepage component

The second component we will create in this React Router tutorial will be component for our homepage. I decided to make this tutorial simple. As a result, the code for all components will use mostly basic HTML code. And, the majority of classes will be from Bootstrap. One exception will be components of React Router and two React methods. These methods are componentWillMount() and componentWillUnmount().

The first method, componentWillMount() will be invoked right before rendering the component itself. The second, componentWillUnmount(), right before the component is destroyed. We will use these methods in every page component to add/remove specific CSS classes to the body element.

JavaScript (React):

// Component for Homepage
class Home extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-home');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-home');
 }

 render() {
  return (
   <div className='container'>
    <div className='row'>
     <div className='col-md-10 push-md-1 col-lg-8 push-lg-2 text-center'>
      <h1>Anthony Sabia</h1>
 
      <p>A web designer &amp; developer from New York, USA, who focuses on building interactive experiences &amp; mobile apps, currently leading a design team at Spotify.</p>
     </div>
    </div>
   </div>
  );
 }
}

About page component

The third component we will create is component for about page. This component will be very similar to homepage. Just the content of HTML will be different.

JavaScript (React):

// Component for About page
class About extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-about');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-about');
 }

 render() {
  return (
   <div className='container'>
    <div className='row'>
     <div className='col-md-10 push-md-1 col-lg-8 push-lg-2'>
      <h1>About Me</h1>

      <p>I like to focus on creating unique and clean design concepts, prototypes and interactive experiences. My expertise and skills cover the whole design process, from research and to visual design and execution.</p>

      <p>I work with a wide range of clients, from startups to well-established companies. My clients are usually looking for user-centered design and product design visions to help them improve their product and grow their brand.</p>
     </div>
    </div>
   </div>
  );
 }
}

Contact page component

Another component we will create for this React Router tutorial will be component for contact page. This component will be a bit different. We will add a short contact form.

JavaScript (React):

// Component for Contact page
class Contact extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-contact');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-contact');
 }

 render() {
  return (
   <div className='container'>
    <div className='row'>
     <div className='col-md-8 push-md-2 col-lg-6 push-lg-3'>
      <h1>Let's get in touch!</h1>

      <form formAction='' className='card-form'>
       <div className='row form-group'>
        <div className='col-6'>
         <input className='form-control' name='formName' id='formName' type='text' placeholder='Your name' />
        </div>

        <div className='col-6'>
         <input className='form-control' name='formEmail' id='formEmail' type='email' placeholder='Your email address' />
        </div>
       </div>

       <fieldset className='form-group'>
        <textarea className='form-control' name='formMessage' id='formMessage' placeholder='Your message' required ></textarea>
       </fieldset>

       <fieldset className='form-group text-center'>
        <button className='btn btn-primary' type='submit'>Send message</button>
       </fieldset>
      </form>
     </div>
    </div>
   </div>
  );
 }
}

Gallery page component

Next is component for gallery page. As I mentioned in the part about CSS, this page will contain nine examples of work (or shots). We will arrange these shots in a grid of three rows, each containing three columns. Every column will contain one shot.

JavaScript (React):

// Component for Gallery page
class Gallery extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-gallery');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-gallery');
 }

 render() {
  return (
   <div className='container'>
    <h1>Featured Projects</h1>

    <p className='mb-4 text-center'>Selection of projects finished between years 2014 — 2016.</p>

    <div className='row'>
     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/40433/screenshots/3205585/dri.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/40433/screenshots/3213974/untitled-1.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/182336/screenshots/3219163/dribbble_shot.png' alt='' />
     </div>
    </div>

    <div className='row'>
     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/692322/screenshots/3217252/profile.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/13307/screenshots/3208495/web_site_tea.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/784847/screenshots/3218599/roposo.com_website_exploration.png' alt='' />
     </div>
    </div>

    <div className='row'>
     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/66340/screenshots/3206003/home.jpg' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/273461/screenshots/3218915/chewy.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/274994/screenshots/3218870/dashboard.png' alt='' />
     </div>
    </div>
   </div>
  );
 }
}

404 page component

The last page component we will create today will be for 404 page.

JavaScript (React):

// Component for NotFound - 404 - page
class NotFound extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-not-found');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-not-found');
 }
 render() {
  return (
   <div className='container'>
    <div className='row'>
     <div className='col-md-10 push-md-1 col-lg-8 push-lg-2 text-center'>
      <h1 className='mt-4 mb-4'>404!</h1>

      <h2>The page you are looking for doesn't exist.</h2>
     </div>
    </div>
   </div>
  );
 }
}

Navigation component

We have components for all pages. However, there is still one component we need to create. This component is for the main navigation. Without it, this React Router tutorial would be quite useless. Well, we could use buttons. However, I think that people are more used to classical navigation. Code for this component will be different from what the code we wrote above. Big part of it, such as classess, nav, li and button elements is default Bootstrap structure.

In addition, we will use two components, from React Router. These components are Link and IndexLink. Partially thanks to these components, we can wire together specific link with specific page. As I mentioned, I added comments to explain how these two components work right into the code ({/* … */}). In a short, Link component works like <a> tag. With React Router, we can use it to render specific page (component).

IndexLink is almost the same as Link. The difference is that this link is active only when the index route is active (URL matches “/”). Otherwise, this link would be active on every page because the URL always contains “/”. The last thing, we are using activeClassName to dynamically append class to the link when it is active – related page is rendered.

JavaScript (React):

// Component for Navigation
class Navigation extends React.Component {
 render() {
  return (
   <nav className='navbar navbar-toggleable-sm'>
    <button className='navbar-toggler navbar-toggler-right' type='button' data-toggle='collapse' data-target='#navbarNav' aria-controls='navbarNav' aria-expanded='false' aria-label='Toggle navigation'>
     <span className='navbar-toggler-icon'></span>
    </button>

    <div className='collapse navbar-collapse justify-content-center' id='navbarNav'>
     <ul className='nav flex-column flex-md-row' role='nav'>
      <li className='nav-item'>
       {/* Note about Links: parent route is active when any child route is active (it has always class ¨'nav-link-active'). We want the link to '/' be active only when the index route is active. For this reason, we will use 'IndexLink' */}
       <IndexLink to='/' className='nav-link' activeClassName='nav-link-active'>Home</IndexLink>
       {/* 'activeClassName' allow us to add class when the link is active (current Route). Another option is using 'activeStyle' and CSS styles. */}
      </li>

      <li className='nav-item'>
       {/* Link is similar to <a/> tag. The difference is that Link is aware of the Router (screen) it is rendered in. It allows you to wire together links with Routes (via 'to' attribute). */}
       <Link className='nav-link' activeClassName='nav-link-active' to='/about'>About</Link>
      </li>

      <li className='nav-item'>
       <Link className='nav-link' activeClassName='nav-link-active' to='/gallery'>Gallery</Link>
      </li>

      <li className='nav-item'>
       <Link className='nav-link' activeClassName='nav-link-active' to='/contact'>Contact</Link>
      </li>
     </ul>
    </div>
   </nav>
  );
 }
}

Ready, set, render!

The last step to get this React Router tutorial up and running is about creating routes and rending them. To do so, we will use Router, Route and IndexRoute components from React Router. We will wrap all Routes and one IndexRoute inside Router. Router will have one attribute – history. This will help us manage the routing history with the hash portion of the URL. Now, can move to Routes.

The difference between Route and IndexRoute is that IndexRoute will allow us to render a component when we visit “/”, or “home” page. Each Route will have two attributes, path and component. Path will specify how will the URL look like. Component will specify what component to render on that URL. IndexRoute will have only one attribute – component. Finally, we need to say where we want the website to be rendered. Let’s use the appRoot variable from the beginning.

JavaScript (React):

ReactDOM.render((
 <Router history={hashHistory}>
  {/* 'hashHistory' manages the routing history with the hash portion of the URL. */}
  <Route path='/' component={App}>
   {/* IndexRoute allows us to render a component when we visit '/'.
   Note: IndexRoute has no path - it becomes this.props.children of the parent when no other child of the parent matches. */}
   <IndexRoute component={Home} />
   {/* Each Route is child of 'App'. This allows the components inside of App share the navigation. Otherwise, we would need to add Navigation compoonent into every page (component) */}
   <Route path='/about' component={About} />
   <Route path='/gallery' component={Gallery} />
   <Route path='/contact' component={Contact} />
   <Route path='*' component={NotFound} />
  </Route>
 </Router>
), appRoot);

All in one piece

Again, let’s put everything together.

JavaScript (React):

// // Store all components of React Router inside variable
const {
 Route,
 Router,
 Link,
 hashHistory,
 IndexRoute,
 IndexLink
} = ReactRouter;

// Store the container for rendering our website
const appRoot = document.querySelector('.appRoot');

// Component for main component
class App extends React.Component {
 render() {
  return (
   <div>
    <Navigation />

    {/* Render active Route or indexRoute */}
    {this.props.children}
   </div>
  );
 }
}

// Component for Homepage
class Home extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-home');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-home');
 }

 render() {
  return (
   <div className='container'>
    <div className='row'>
     <div className='col-md-10 push-md-1 col-lg-8 push-lg-2 text-center'>
      <h1>Anthony Sabia</h1>
 
      <p>A web designer &amp; developer from New York, USA, who focuses on building interactive experiences &amp; mobile apps, currently leading a design team at Spotify.</p>
     </div>
    </div>
   </div>
  );
 }
}

// Component for About page
class About extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-about');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-about');
 }

 render() {
  return (
   <div className='container'>
    <div className='row'>
     <div className='col-md-10 push-md-1 col-lg-8 push-lg-2'>
      <h1>About Me</h1>

      <p>I like to focus on creating unique and clean design concepts, prototypes and interactive experiences. My expertise and skills cover the whole design process, from research and to visual design and execution.</p>

      <p>I work with a wide range of clients, from startups to well-established companies. My clients are usually looking for user-centered design and product design visions to help them improve their product and grow their brand.</p>
     </div>
    </div>
   </div>
  );
 }
}

// Component for Contact page
class Contact extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-contact');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-contact');
 }

 render() {
  return (
   <div className='container'>
    <div className='row'>
     <div className='col-md-8 push-md-2 col-lg-6 push-lg-3'>
      <h1>Let's get in touch!</h1>

      <form formAction='' className='card-form'>
       <div className='row form-group'>
        <div className='col-6'>
         <input className='form-control' name='formName' id='formName' type='text' placeholder='Your name' />
        </div>

        <div className='col-6'>
         <input className='form-control' name='formEmail' id='formEmail' type='email' placeholder='Your email address' />
        </div>
       </div>

       <fieldset className='form-group'>
        <textarea className='form-control' name='formMessage' id='formMessage' placeholder='Your message' required ></textarea>
       </fieldset>

       <fieldset className='form-group text-center'>
        <button className='btn btn-primary' type='submit'>Send message</button>
       </fieldset>
      </form>
     </div>
    </div>
   </div>
  );
 }
}

// Component for Gallery page
class Gallery extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-gallery');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-gallery');
 }

 render() {
  return (
   <div className='container'>
    <h1>Featured Projects</h1>

    <p className='mb-4 text-center'>Selection of projects finished between years 2014 — 2016.</p>

    <div className='row'>
     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/40433/screenshots/3205585/dri.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/40433/screenshots/3213974/untitled-1.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/182336/screenshots/3219163/dribbble_shot.png' alt='' />
     </div>
    </div>

    <div className='row'>
     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/692322/screenshots/3217252/profile.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/13307/screenshots/3208495/web_site_tea.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/784847/screenshots/3218599/roposo.com_website_exploration.png' alt='' />
     </div>
    </div>

    <div className='row'>
     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/66340/screenshots/3206003/home.jpg' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/273461/screenshots/3218915/chewy.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/274994/screenshots/3218870/dashboard.png' alt='' />
     </div>
    </div>
   </div>
  );
 }
}

// Component for NotFound - 404 - page
class NotFound extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-not-found');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-not-found');
 }
 render() {
  return (
   <div className='container'>
    <div className='row'>
     <div className='col-md-10 push-md-1 col-lg-8 push-lg-2 text-center'>
      <h1 className='mt-4 mb-4'>404!</h1>

      <h2>The page you are looking for doesn't exist.</h2>
     </div>
    </div>
   </div>
  );
 }
}

// Component for Navigation
class Navigation extends React.Component {
 render() {
  return (
   <nav className='navbar navbar-toggleable-sm'>
    <button className='navbar-toggler navbar-toggler-right' type='button' data-toggle='collapse' data-target='#navbarNav' aria-controls='navbarNav' aria-expanded='false' aria-label='Toggle navigation'>
     <span className='navbar-toggler-icon'></span>
    </button>

    <div className='collapse navbar-collapse justify-content-center' id='navbarNav'>
     <ul className='nav flex-column flex-md-row' role='nav'>
      <li className='nav-item'>
       {/* Note about Links: parent route is active when any child route is active (it has always class ¨'nav-link-active'). We want the link to '/' be active only when the index route is active. For this reason, we will use 'IndexLink' */}
       <IndexLink to='/' className='nav-link' activeClassName='nav-link-active'>Home</IndexLink>
       {/* 'activeClassName' allow us to add class when the link is active (current Route). Another option is using 'activeStyle' and CSS styles. */}
      </li>

      <li className='nav-item'>
       {/* Link is similar to <a/> tag. The difference is that Link is aware of the Router (screen) it is rendered in. It allows you to wire together links with Routes (via 'to' attribute). */}
       <Link className='nav-link' activeClassName='nav-link-active' to='/about'>About</Link>
      </li>

      <li className='nav-item'>
       <Link className='nav-link' activeClassName='nav-link-active' to='/gallery'>Gallery</Link>
      </li>

      <li className='nav-item'>
       <Link className='nav-link' activeClassName='nav-link-active' to='/contact'>Contact</Link>
      </li>
     </ul>
    </div>
   </nav>
  );
 }
}

ReactDOM.render((
 <Router history={hashHistory}>
  {/* 'hashHistory' manages the routing history with the hash portion of the URL. */}
  <Route path='/' component={App}>
   {/* IndexRoute allows us to render a component when we visit '/'.
   Note: IndexRoute has no path - it becomes this.props.children of the parent when no other child of the parent matches. */}
   <IndexRoute component={Home} />
   {/* Each Route is child of 'App'. This allows the components inside of App share the navigation. Otherwise, we would need to add Navigation compoonent into every page (component) */}
   <Route path='/about' component={About} />
   <Route path='/gallery' component={Gallery} />
   <Route path='/contact' component={Contact} />
   <Route path='*' component={NotFound} />
  </Route>
 </Router>
), appRoot);

Closing thoughts on React Router

This is it! You’ve just created your own website using React Route! From now on, you can build websites and apps that don’t require reloading the page. In the end, it wasn’t that hard. Or was it? I hope that you had fun while working on this tutorial. Also, I hope you learned something new, something you can know use elsewhere. That’s all for today. See you here again on Friday!

If you liked this article, please subscribe so you don't miss any future post.

If you'd like to support me and this blog, you can become a patron, or you can buy me a coffee 🙂

By Alex Devero

I'm Founder/CEO of DEVERO Corporation. Entrepreneur, designer, developer. My mission and MTP is to accelerate the development of humankind through technology.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.