React is a JavaScript library for building user interfaces. With the React paradigm, every piece of the UI is a component that manages it's on self-contained state (data) and functions.
React like other front-end JavaScript frameworks are useful for creating Single Page Applications (SPAs). These are web apps that do not need a full page reload on change of view, instead, they swap views into or out from a section of the page as the user navigates through the app.
Though SPAs provide a fluid navigation experience for users, routing features of traditional websites are expected. For instance:
- every view on the screen should have its own specific URL so I can bookmark the page.
- The forward and back button should move me forward or backward in my browsing history.
- Nested views and those with parameters should be supported. e.g example.com/products/shoes/101
In the React community, React Router is the favorite library for handling routing. The most compelling aspect of this version of the library is that it’s “just React”. The routes are just components that get rendered to the screen when the app is running. They are not defined in external files as done in other frameworks.
Prerequisites
You will need the following: Basic knowledge of React, Git installed on your computer, and NPM installed on your computer.
First of all, locate the empty source files (at the master branch)if you have git installed and clone to your computer using:
Open the folder in your text editor and discover the sub-folders inside.
This post is divided into four subsections according to the folders which are: Basic routing, Nested routing, Nested routing with path parameters and Authenticated routing.
To launch the demos, open a given folder in your terminal then run npm install
followed by npm start
.
#1. Basic routing
All the demos in this post have been initially created using create-react-app. This brings some benefits such an already configured webpack server that would bundle all the javascript file in our app into a bundle.jsfile that would be attached into the index.html file at run time. Webpack’s dev server when run will listen to any change in our file and update it as the app runs during development.
I’ve created a components/folder to keep all our components. Note that:
- index.js is the entry file to all .js files in our app. This is where Webpack’s bundling will be performed so all .js files should be imported into it.
- App.js file would contain everything pertaining to our React app.
By default, create-react-app does not place App.js in this folder but because I’ve modified the folder structure, I made appropriate changes to the path url importing it into index.js. To learn more about Create-react-app, the reference would be helpful.
Navigate to the first folder (01-basic-routing) and run npm install
.
Open the App.js
file and you should see the following:
import '../styles/App.css';
// import route Components here
class App extends Component {
render() {
return (
<div className="App">
<div className="container">
<ul>
<li><a href="">Hello</a></li>
<li><a href="">About</a></li>
<li><a href="">Books</a></li>
</ul>
<hr/>
{/* Routes will go here */}
</div>
</div>
);
}
}
export default App;
Run npm start and view the app. No changes made yet.
No changes made
Let's install React Router via NPM. With the folder open in your terminal, run
Why react-router-dom? This is because the React router library comprises of three packages: react-router
, react-router-dom
, and react-router-native
. react-router
is the core package for the router, whereas the other two are environment specific. You should use react-router-dom
if you’re building for the web, and react-router-native
if you’re on a mobile app development environment using React Native.
Import the following into App.js
import {
BrowserRouter as Router,
Route,
Link,
Switch,
Redirect
} from 'react-router-dom'
Later on, we would get to understand what those components do. All of the routing components depend on BrowserRouter
to provide the browser’s HTML5 History APIs to them.
Note that React components have their first letter capitalized so as to identify them differently from default HTML tags.
The History API is an object that lets us manage the current location viahistory.location
as well as previous locations. Think of thelocation
property of the object as an array. The current location is the last item on the array and we manipulate the array through methods such ashistory.push()
orhistory.replace
. Whatever manipulation is made on the array will trigger a page transition to the current location. This is what happens behind the scene when usingLink
andRedirect
component as we’ll see soon.
We’ve imported the contents of BrowserRouter
into Router
variable. We need to wrap our entire app with it so it supplies the needed APIs all throught the app. In app.js do so:
import '../styles/App.css';
// import route Components here
import {
BrowserRouter as Router,
Route,
Link,
Switch,
Redirect
} from 'react-router-dom'
class App extends Component {
render() {
return (
<Router>
<div className="App">
<div className="container">
<ul>
<li><a href="">Hello</a></li>
<li><a href="">About</a></li>
<li><a href="">Books</a></li>
</ul>
<hr/>
{/* Routes will go here */}
</div>
</div>
</Router>
);
}
}
export default App;
The <Route /> component .
Lets begin exploring theRoute
component. This component renders a page if the current URL location matches thepath
prop specified in it. It also acceptscomponent
,render
andchildren
props.
Let's create ours where its written {/* Routes will go here */}:
<Route path="/about" component={About} />
<Route path="/books" component={Books} />
But those components don’t exist! Yes, you are right. Again before we create them, lets add more imports to App.js
. Import from the HelloComponent.js
, AboutComponent.js
, and BooksComponent.js
using Hello
, About
, and Books
as variables. The component={}
prop uses curly braces to refer to variables not strings.
import '../styles/App.css';
import About from './AboutComponent';
import Books from './BooksComponent';
import {
BrowserRouter as Router,
Route,
Link,
Switch,
Redirect
} from 'react-router-dom'
Note that render
is similar to component={}
but it lets us define a component inline and right there:
return (
<div className="jumbotron">
<h1 className="display-3">Hello, world!</h1>
</div>
);
}}/>
Head over to the empty HelloComponent.js
file and paste:
return (
<div className="jumbotron">
<h1 className="display-3">Hello, world!</h1>
</div>
);
}
We used a Stateless functional component (hence the arrow function) above. We use them for components that render only static content to a webpage as opposed to components that render stateful/changing content.
If you didn’t notice, we are using bootstrap 4 styles in our App.css
file hence the jumbotron
class in the div
.
padding-top: 50px;
}
Head over to the empty AboutComponent.js
file and paste:
return (
<div className="jumbotron">
<h1 className="display-3">About Me</h1>
</div>
);
}
Finally, Head over to the empty BooksComponent.js
file and paste:
return (
<div className="jumbotron">
<h1 className="display-3">My Books</h1>
</div>
);
}
One more thing we need to wrap up this section is the Link
component.
The <Link></Link> Component
This is replaces the default<a href=""></a>
HTML tag. It accepts ato=""
prop that points to the URL location we want to go to.
Inside app.js
, replace the default anchor tags with Link
:
<li><Link to="/hello">Hello</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/books">Books</Link></li>
</ul>
Run npm start
from your terminal and see the complete app.
Using Route and Link
How would you render a component if the /
URL is visited i.e the landing or home page. Your guess may be to create a route for it:
This is fine but remember that the other paths have /
in them. So if we visited other URLs such as /hello
, /about
and /books
, theHome
component will keep being rendered by default. To fix this, write another prop exact
setting it to true
or just write exact
.
This would ensure to Home
component is rendered only in cases where the URL exactly matches this:/
.
only if the URL matches the path exactly.
Create a new HomeComponent.js
file in components/ folder. Paste this in:
return (
<div className="jumbotron">
<h1 className="display-3">Landing page</h1>
</div>
);
}
Import into App.js
Add to the list of routes
<Route path="/hello" component={Hello} />
<Route path="/about" component={About} />
<Route path="/books" component={Books} />
Visit http://localhost:3000
and view
Home component rendered on ‘/’ path
Do some experiment. Remove exact={true}
from Home route and see what happens. You’ll see why its important.
Always use exact={true} on the ‘/’ path, else every <Route /> will render.
The <Switch></Switch> Component
This will require being wrapped aroundRoute
components when needed for implementation. When a URL path is visited, it allows only the first<Route>
that matches the path to be rendered.
Earlier we had an issue with /
rendering the Home
component and that of other paths. If we create a /hello/goodmorning
path, what will happen? The components of the /hello
and /hello/goodmorning
path will be rendered. Switch will help in this case again by choosing only one route to render but the most important route must be arranged to come first.
Just an experiment
Using Switch
, we can avoid what happens in the image above but only for URLs other than /
. exact={true}
handles it for /
. Remember that Switch
will pick only the first matching Route
. Lets put it to work and see the result.
<Route exact path="/" component={Home} />
<Route path="/hello" component={Hello} />
<Route path="/hello/goodmorning" render={() => { return <h1>Goodmorning</h1> }} />
<Route path="/books" component={Books} />
</Switch>

Furthermore, Switch
allows us to specify a route to render if the URL matches no location. For that route, leave the path
prop empty.
<Route component={NoMatch} />
In summary, Switch
will do the following:
- avoid inclusive route rendering.
- include a catch-all Route at the bottom of our Switch container.
#2. Nested routing
Remember that we could render components via Route
inline or by specifying the component:
Or
The component that will be created via Route
will automatically be passed the followingprop
objects:
- match
- location
- history
We will only explore the use of match
as it is helpful for implementing nested routes. The match
object contains the following properties:
- params — (object) Key/value pairs parsed from the URL corresponding to the dynamic segments of the path.
- isExact — (boolean) true if the entire URL was matched (no trailing characters).
- path — (string) The path pattern used to match. Useful for building nested <Route>s
- url — (string) The matched portion of the URL. Useful for building nested <Link>s
We want to add new routes under the /book
route. They will be books:
- HTML
- CSS
- React
Navigate to the second sub-folder (02-nested-routing)on your terminal and run npm install
.
In your code editor, open BookComponent.js
and modify:
return (
<div>
<div className="jumbotron">
<h1 className="display-3">My Books</h1>
</div>
<div className="row">
<ul>
<li><Link to="">HTML</Link></li>
<li><Link to="">CSS</Link></li>
<li><Link to="">React</Link></li>
</ul>
</div>
<div className="col-md-9">
</div>
</div>
);
}
We’ve demonstrated syntactically that the match
object is passed as props
. Remember that the classes used as for Bootstrap’s styles to take effect. Don’t forget to import all React Router components after importing React:
import {
BrowserRouter as Router,
Route,
Link,
Switch,
Redirect
} from 'react-router-dom';
We didn’t need to import all of them but we did anyway. Place the routes:
<Route path="" render={() => { return <h1>CSS by Racheal Andrews</h1> }}/>
<Route path="" render={() => { return <h1>React by Fullstack.io book</h1> }}/>
We are using inline component rendering to save time. Now, lets populate the to=""
of Link
and path=""
of Route
. Make these changes:
<ul>
<li><Link to={`${match.url}/html`}>HTML</Link></li>
<li><Link to={`${match.url}/css`}>CSS</Link></li>
<li><Link to={`${match.url}/react`}>React</Link></li>
</ul>
</div>
<div className="col-md-9">
<Route path={`${match.path}/css`} render={() => { return <h1>CSS by Racheal Andrews</h1> }}/>
<Route path={`${match.path}/react`} render={() => { return <h1>React by Fullstack.io book</h1> }}/>
${match.url}
evaluates to /books
and ${match.path}
evaluates to localhost://3000/books.
The back ticks used are ES6’s way of concatenating strings containing variables.
Give it a save, run npm start
and vie the working app.
Nested routes
#3. Nested routing with path parameters
Any URL that ends with /:id
,/:user
or /:whatever
indicates that that portion is a dynamically generated part of the URL that could be any value.
We can access such portions via match.params.id
for use in routing.
Again open the third folder in your terminal and run npm install
.
To illustrate the how path parameters can be used for routing, pate the following in App.js
:
import {
BrowserRouter as Router,
Route,
Link,
Switch,
Redirect
} from 'react-router-dom';
return (
<div>
<div className="jumbotron">
<h1 className="display-3">My Books</h1>
</div>
<div className="row">
<div className="col-md-3">
<ul>
<li><Link to={`${match.url}/html`}>HTML</Link></li>
<li><Link to={`${match.url}/css`}>CSS</Link></li>
<li><Link to={`${match.url}/react`}>React</Link></li>
</ul>
</div>
<div className="col-md-9">
<Route path={`${match.path}/html`} render={() => { return <h1>HTML by Ducket book</h1> }}/>
<Route path={`${match.path}/css`} render={() => { return <h1>CSS by Racheal Andrews</h1> }}/>
<Route path={`${match.path}/react`} render={() => { return <h1>React by Fullstack.io book</h1> }}/>
<Route path={`${match.path}/:id`} component={Child} />
</div>
</div>
</div>
</div>
);
}
<div>
<h3>URL ID parameter: {match.params.id}</h3>
</div>
);
Run npm start.

accessing /:id parameter value
#4. Protected path routing
This kind of routing is for pages of a website that need the user to login and be authentication before viewing such pages. An example is an Admin page.
To handle protected paths, we’ll need to use <Redirect/>
(a standard component)and <PrivateRoute/>
(a custom component).
<PrivateRoute/>
is not the standard <Route/>
component. The standard route component provided by React Router is<Route/>
. We will define <PrivateRoute/>
as our own custom <Route/>
.
Custom routes are necessary when we need to make a decision whether a <Route/>
of interest should be rendered or not. A route determining whether a route hsould be rendered. As you’ll see in the code, we will list <PrivateRoute/>
together with other <Route/>
s.
The <Redirect/> component
Rendering a <Redirect> will navigate to a new location. The new location will override the current location in the history stack, like server-side redirects (HTTP 3xx) do.
<Redirect/>
a couple of props but we will be using the to
object prop this way:
pathname: '/login',
state: { from: props.location }
}}/>
When used, this will redirect to the /login
path. Information about the last location before the redirect was done will be accessible by the LoginPage
component via this.props.location.state
.
Navigate to the last demo folder (04-authenticated-routing). Run npm install
. Open App.js
and add a new list /admin
item to the existing ones.
<li><Link to="/hello">Hello</Link></li>
<li><Link to="/about">About</Link></li>
<li>
<Link to="/books">Books</Link>
</li>
<li>
<Link to="/admin">Admin</Link>
</li>
</ul>
Add <PrivateRoute/>
and /login
route to the group of existing <Route/>s.
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/hello" component={Hello} />
<Route path="/books" component={Books} />
<Route path="/login" component={Login}/>
<PrivateRoute authed={fakeAuth.isAuthenticated} path="/admin" component={Admin} />
</Switch>
Now actually create the <PrivateRoute/>
component outside of App
component:
<Route {...rest} render={props => (
fakeAuth.isAuthenticated ? (
<Component {...props}/>
) : (
<Redirect to={{
pathname: '/login',
state: { from: props.location }
}}/>
)
)}/>
)
<PrivateRoute/>
will eventually render down to a <Route>
component. The <Route>
component uses a ternary operation to determine what to render based on whether the user is logged in or not: a <Redirect/>
to the login page or Admin
page component.
Create the Admin
component:
return (
<div className="jumbotron">
<h3 className="display-3">Admin Access granted</h3>
</div>
);
}
Also, create the Login component:
super();
redirectToReferrer: false
}
// binding 'this'
this.login = this.login.bind(this);
}
this.setState({ redirectToReferrer: true })
})
}
const { from } = this.props.location.state || { from: { pathname: '/' } }
const { redirectToReferrer } = this.state;
return (
<Redirect to={from} />
)
}
<div className="jumbotron">
<h1 className="display-3">Login required</h1>
<p className="lead">You must log in to view the page at {from.pathname}.</p>
<p className="lead">
<a className="btn btn-primary btn-lg" onClick={this.login} role="button">Login</a>
</p>
</div>
)
}
}
export const fakeAuth = {
authenticate(cb) {
this.isAuthenticated = true
setTimeout(cb, 100)
},
}
This Login
component implements a fake authentication function that will set make a user either logged in or out.
Run npm start
and see the working app.
Authentication Process
This brings us to the end of the article. Kudos to you if you made it this far. If you would like more details about React Router, view the Documentations.
Feel free to Comment or Share this post. Thanks for reading!
Leave a Reply
Your email address will not be published. Required fields are marked *