Routing is a necessity when it comes to JavaScript-based single-page applications (SPAs). At some point, your app is going to need navigation. The way SPAs work is by sending the compiled and minified JavaScript file over with the HTML and CSS, then proceeds to render the site with lazy loading techniques to provide the user with a just-in-time browsing experience.
Routing is the technique that gives the impression of the app or website multiple pages or views. However, in reality, it’s all still just the same original page sent from the server-side. All the processing is completed on the client-side in a seamless manner.
So how does routing and redirecting work in React?
Unlike Angular and other JavaScript-based SPA frameworks, React doesn’t come with a pre-built routing system. React, after all, just a UI library. This means that its sole purpose is to help developers organize and render UI in the most effective and efficient manner. Routing is considered an extra feature.
However, the perks of React is that it has a strong developer community, meaning that common development needs — such as routing — have already been addressed via an add-on library to React.
In our case, it’s called React Router.
There are two ways you can install React Router into your React project. The first method is to add it to your project repository via yarn.
yarn add react-router-dom
Alternatively, you can do so using npm install
npm install react-router-dom
Debugging notes:
You might run into a potential conflict with babel jest when you try to use React Router. It’s similar to the issue that occurs when you install node-sass. You’ll see the conflict pop up in your console when you try to start your React application.
When this happens, it’s because the dependencies of babel jest are different from the react-router library we’ve just installed. If you look at the actual error, most of the time, it’s not the major versions that are in conflict with one another — rather, it’s the minor trailing updated versions.
To fix this, go inside your packages.json
and add a resolutions
property and tell it that we always want babel jest to be a specific version no matter what.
Here is an example of what this might look like:
... "devDependencies":{ "react-scripts": "3.0.0" }, "resolutions":{ "babel-jest":"24.7.1" } ...
After you’ve done this, save your file and reinstall your React Router library. Once this is completed, you should have no problem starting your application.
Before you can begin to use routing in your React app, you need to go to your index.js
and import in BrowserRouter
.
It looks something like this:
import React from 'react'; import ReactDOM from 'react-dom'; import { BrowserRouter } from 'react-router-dom';
BrowserRouter
is actually a component that you can use to wrap around your application to make routing possible. What this does is give your <App />
component all the functionality available within BrowserRouter
.
Here is how it looks in the code:
... ReactDOM.render( <BrowserRouter> <App /> </BrowserRouter>, document.getElementById('root') ); ...
So how do you use it in an actual component? Let’s do an example route inside your App.js
.
Start by importing Route
into your component.
... import { Route } from 'react-router-dom'; ...
Now we’re going to make a quick component that renders out a <div>
.
const catsPage = () => ( <div> <h1>CATS!</h1> </div> )
This component is going to represent another page that’s alternate to our base rendered homepage. Here’s the code for that part.
function App() { return ( <div> <HomePage /> </div> ) }
Note: We’re going to pretend that your <HomePage />
lives in another file and pulled into this file via import
.
The route component works by taking a few arguments. The main ones for this tutorial that we’re going to focus on are exact
, path
, and component
.
Here’s a breakdown of what they do:
component:
component is what we want the route to render.
path:
the string that we want our string to equal to based on where we currently are. For example, if our component={HomePage}
, then we might want our path to be path='/'
, which is the base of our application.
exact:
this is a true
or false
boolean property. If you don’t assign anything to it, then it will default to true. exact
tells the app that the path
must be exactly what you set it as in order for the assigned component to render.
Here is what it looks like in the React code if we swap out <HomePage />
as per the code block example above:
function App() { return ( <div> <Route exact path='/' component={HomePage} /> </div> ) }
In the example above, if you had something like localhost:3000/
, then it will render the HomePage
component as expected.
But what happens if you remove exact
from Route
? You might have a link like localhost:3000/random
and React Router library will still evaluate that as true
and end up showing the HomePage
component.
Now, this is where the fun part begins. If we created another route
in React without using exact
, what will happen is that React will render whatever comes up as true
.
Let’s take a look at the follow block of example code:
function App() { return ( <div> <Route path='/' component={HomePage} /> <Route path='/cats' component={CatsPage} /> </div> ) }
Without exact, the link localhost:3000/cats
will evaluate HomePage
to true
and render it, followed by CatsPage
directly beneath it. Without exact
in React Router, as long as the path matches (even if it’s just a partial match), it will evaluate to true
and render.
However, if you throw in exact
, then it will have to be exactly as-is stated. So, for example, if you throw exact
back into the route
for HomePage
, it won’t render when you try localhost:3000/cats
because it’s not an exact match.
To use the Switch
component, we need to add it to the import like so:
... import { Route, Switch } from 'react-router-dom'; ...
And then wrap your <Route />
components within <Switch>
like this:
function App() { return ( <div> <Switch> <Route path='/' component={HomePage} /> <Route path='/cats' component={CatsPage} /> </Switch> </div> ) }
What <Switch>
does is that when a route inside the <Switch>
tag pair finds a match in the path, it does not render anything else but that route. So, before, when we didn’t have exact
as a property inside our <Route />
, localhost:3000/cats
will render both HomePage
and CatsPage
.
However, if we use <Switch>
, it will match / first
and not render anything else that may also evaluate to true
. This means that if we tried to go to localhost:3000/cats
, only our HomePage
will show up.
So when we put exact
back into <Route exact path='/' component={HomePage} />
, then it will only render CatsPage
. In short, you can think of <Switch>
as a first match route rendering tool. <Switch>
comes in handy when we don’t want to accidentally render multiple components that may have matching paths.
With the combination of <Route>
and <Switch>
, this is conceptually what routing is in React.
When <Route>
renders a component for us, the component itself also gets passed three arguments. So, for example, <Route path='/' component={HomePage} />
will have the following arguments in the props — history
, location
, and match
. For this section, we’re going to focus on match
.
Inside our match
, we get four things and they are url
, path
, params
, and isExact
. The url
is the url of the component that it got rendered up to from the route. In our previous examples, we know that any path without exact
will be partially matched. The url
inside match
tells us what portion of the url
we’ve put into the browser is the valid part that evaluated it to true
. The path
inside match
is just telling us the pattern that the url
is trying to match.
The isExact
is only true if the url
matches the entire path pattern. Where does this come in handy?
When we use <Route />
without exact
, it will render anything that matches. This means, for our HomePage
and CatsPage
example, if we had localhost:3000/cats
without using exact
, isExact
under HomePage
will display as false
while CatsPage
will return true
. This gives us granularity in the future to use for whatever we might need to.
Finally, the params
property is an object of url parameters. What is a url parameter? Here is an example:
<Route path='/cats/:catName' component={CatPage} />
The url
parameter in the code above is :catName
. :catName
represents a dynamically changing value that can be anything we want it to be. This property is also accessible as a parameter via the params
property under match
.
So if we wanted to use this parameter, we can do so via props
in our React code.
Here is an example:
const CatPage = props => { return( <div> <h1>Hello, my name is {props.match.params.catName}</h1> </div> ); };
Other spaces you might use params
is when you want to fetch some data relating to the page, you have the details necessary to fetch through API calls to your backend.
And that’s basically it for React Routing and redirecting in React in a nutshell. The explanations and examples here here should be enough to get you started on creating your own routes in React quickly and efficiently.