If you decide to use React for your application, you will likely be building a Single Page Application(SPA). As your application grows, you will want your app to have multiple URLs that contain different components. This is where client-side routing comes in.
The major benefit of client-side routing is speed. Using client-side routing, the whole application is loaded on the first GET
request. Because of this, it can take a while when the application first mounts, but then we don't have to wait for a round trip server call for each page change after that.
React Router is the most popular routing library for React. It allows you to create intuitive routes that are human-readable so it will be easy to manage the application structure.
I am going to walk you through how to implement client-side routing in a React application using React Router step by step.
Installation
In your application, run this:
$ npm install --save react-router-dom
Or, if you are using yarn, run:
yarn add react-router-dom
Implementation
Add routes
Let's first create the <Home>
page and add /home
routes in our application so we can go to http://localhost:3000/home
to see the <Home>
page.
Here is our simplest <Home>
page:
// myapp/src/components/Home.js
import React from 'react'
const Home = () => {
return (
<>
<h1>Home page</h1>
<h3>Welcome to my app!</h3>
</>
)
}
export default Home
Now, in App.js
, let's set up a route to load the Home
component:
// myapp/src/App.js
import React from 'react'
import { BrowserRouter, Route } from 'react-router-dom'
import Home from './components/Home'
const App = () => {
return (
<>
<h1>My App</h1>
<BrowserRouter>
<Route path="/home" component={Home} />
</BrowserRouter>
</>
)
}
export default App
Great! The <BrowserRouter>
component creates a base router and the <Route>
component configures each route and specifies the component that should render.
Let's also create <AboutUs>
and <Contact>
pages and add /about
and /contact
routes as well:
// myapp/src/components/AboutUs.js
import React from 'react'
const AboutUs = () => {
return (
<h1>About us</h1>
)
}
export default AboutUs
// myapp/src/components/Contact.js
import React from 'react'
const Contact = () => {
return (
<h1>Contact page</h1>
)
}
export default Contact
// myapp/src/App.js
import React from 'react'
import { BrowserRouter, Route } from 'react-router-dom'
import Home from './components/Home'
import Contact from './components/Contact'
import AboutUs from './components/AboutUs'
const App = () => {
return (
<>
<h1>My App</h1>
<BrowserRouter>
<Route path="/home" component={Home} />
<Route path="/about" component={AboutUs} />
<Route path="/contact" component={Contact} />
</BrowserRouter>
</>
)
}
export default App
Exact path
Hmmm, this is not exactly what we want. We want to show <Contact>
page only when we go to /contact
. In this case, we can use the exact
attribute:
// myapp/src/App.js
import React from 'react'
import { BrowserRouter, Route } from 'react-router-dom'
import Home from './components/Home'
import Contact from './components/Contact'
import AboutUs from './components/AboutUs'
const App = () => {
return (
<>
<h1>My App</h1>
<BrowserRouter>
<Route path="/home" component={Home} />
<Route path="/about" component={AboutUs} />
<Route exact path="/contact" component={Contact} />
</BrowserRouter>
</>
)
}
export default App
Great! Now /contact/something
path doesn't render <Contact>
component.
Use <Switch>
to set up exclusive routes
What if you change your mind and you want to add home/about
instead of /about
? Sure, we can do that. But first, you need to know how <Switch>
works.
<Switch>
works as the switch
statement in JavaScript. It checks the path, and, as soon as it finds a match, it breaks out of the block. Let me show you what would be a problem without using <Switch>
:
// myapp/src/App.js
import React from 'react'
import { BrowserRouter, Route } from 'react-router-dom'
import Home from './components/Home'
import Contact from './components/Contact'
import AboutUs from './components/AboutUs'
const App = () => {
return (
<>
<h1>My App</h1>
<BrowserRouter>
<Route path="/home" component={Home} />
<Route path="/home/about" component={AboutUs} />
<Route exact path="/contact" component={Contact} />
</BrowserRouter>
</>
)
}
export default App
Oh no. Why do we see the <Home>
component too? This happens because of the way JavaSript matches strings.
> "/home".match("/home/about")
null
If I match /home
with /home/about
, it returns null
. On the other hand, if I match /home/about
with /home
:
> "/home/about".match("/home")
[ '/home', index: 0, input: '/home/about', groups: undefined ]
I get a truthy value. This is why /home/about
renders both <Home>
and <AboutUs>
components. We can avoid this using <Switch>
because it breaks after the first match found. Don't forget to put the most specific routes first and more general routes second since <Switch>
matches from the top.
// myapp/src/App.js
import React from 'react'
import { BrowserRouter, Route, Switch } from 'react-router-dom'
import Home from './components/Home'
import Contact from './components/Contact'
import AboutUs from './components/AboutUs'
const App = () => {
return (
<>
<h1>My App</h1>
<BrowserRouter>
<Switch>
<Route path="/home/about" component={AboutUs} />
<Route path="/home" component={Home} />
<Route exact path="/contact" component={Contact} />
</Switch>
</BrowserRouter>
</>
)
}
export default App
In the next article, I will introduce how to set up routes with parameters using React Router.
Top comments (0)