React Hooks were introduced with the release of React 16.8.0 to much excitement. With Hooks, developers can write cleaner components with less boilerplate compared to a class component. Many popular React packages are adding support for Hooks so developers can leverage their APIs in functional components.
React Router, the go-to routing solution for React Apps, added Hooks support in its version 5 release. These React Router Hooks provide developers with new ways to handle the router state.
In this tutorial, we’ll show you how to use Hooks with React Router and minimize code lines in a component.
How Hooks work with React Router
To demonstrate how Hooks work, we’ll create a React project and set up the pages.
To create a React app, run the following command:
npx create-react-app router-hooks-demo
Note that router-hooks-demo
is the name of the app for this guide; you can change the name as you wish.
Next, add the react-router-dom
package:
npm i react-router-dom --save
Import BrowserRouter
, Link
, Route
, and Switch
components from the react-router-dom
package. These components will be used to configure client-side routing in the React app.
import { BrowserRouter, Link, Route, Switch } from "react-router-dom";
For this demo, you’ll only have two routes, or pages: the home page and user page. You’ll mainly be working on the user page.
const User = () => { return <div>This is the user page</div>; }; const Home = () => { return <div>This is the home page</div>; };
In the App
component, create a navigation bar section and add hyperlinks to the pages using the Link
component. On the webpage, the Link
component gets rendered as a <a>
tag.
<nav> <div> <Link to="/">Home</Link> </div> <div> <Link to="/user/:id">User</Link> </div> </nav>
Next, add the Switch
and Route
component, and wrap everything in the BrowserRouter
component.
<BrowserRouter> <nav> <div> <Link to="/">Home</Link> </div> <div> <Link to="/user/:id">User</Link> </div> </nav> <Switch> <Route path="/user"> <User /> </Route> <Route path="/" exact> <Home /> </Route> </Switch> </BrowserRouter>
The BrowserRouter
component enables the client-side routing feature and handle the routing logic using the browser history
API. The Route
component renders the page UI when the route path matches the active URL. The Switch
component only allows the first matched path to be rendered.
If you have a bunch of Route
components that match the same URL, you’ll end up rendering all the routes, which is not expected. Only one route should be rendered for a URL.
The final App.js
file should look like this:
import React from "react"; import { BrowserRouter, Link, Route, Switch } from "react-router-dom"; const User = () => { return <div>This is the user page</div>; }; const Home = () => { return <div>This is the home page</div>; }; export default function App() { return ( <div className="App"> <BrowserRouter> <nav> <div> <Link to="/">Home</Link> </div> <div> <Link to="/user/:id">User</Link> </div> </nav> <Switch> <Route path="/user/:id"> <User /> </Route> <Route path="/" exact> <Home /> </Route> </Switch> </BrowserRouter> </div> ); }
Why React Router Hooks are useful
Let’s say you need to access the current pathname of the URL inside a page component. Before Hooks, you would have to pass the page component to the component
prop of the Route
component. Then the Route
component would inject with route props: match
, location
, and history
.
This is fine, but the component becomes harder to read and it’s difficult to understand how the props are injected when it comes to maintaining the project. The React Router authors added Hooks support so the page components can access history
, location
, and match
objects without having to pass the page component as a component prop in the Route
component.
// Route with component prop <Route path="/user/:id" component={User} />; // User component const User = (props) => { const location = props.location; console.log(location.pathname); return <div>This is the user page</div>; };
React Router Hooks
Now that you understand why Hooks are added for routing, let’s see the Hooks in action.
useParams
The useParams
Hook returns an object containing key-value pairs of the passed parameters in a dynamic URL.
For example, let’s say you have a User
page component that accepts an id
as a param in the URL.
<Route path="/user/:id"> <User /> </Route>
Import the useParam
Hook from react-router-dom
package.
import { useParams } from "react-router-dom";
Now you can use the Hook, as shown below.
const User = () => { const params = useParams(); console.log(params); return ( // ... ) }
So if you were to pass 3
as ID in the user URL (/user/3
), the useParam()
would return an object as follows:
{ id: 3, }
You can use this id
param to display on the page or fetch the user information from the server.
import { // ... useParams, } from "react-router-dom"; // /user/:id const User = () => { const params = useParams(); return ( <div> <div>This is the user page</div> <div>current user Id - {params.id}</div> </div> ); };
useHistory
The useHistory
Hooks return the history
object, which the router uses internally to handle the route changes. The history
object is used for managing session history.
For example, you can use the history.push()
method to add a new entry to the history stack and navigate the user from the current route:
import { // ... useHistory, } from "react-router-dom"; const User = () => { const history = useHistory(); const params = useParams(); const handleBack = () => { history.goBack(); }; const handleNavigation = () => { history.push("/user/5"); }; return ( <div> <div>This is the user page</div> <div>current user Id - {params.id}</div> <div> <button onClick={handleBack}>Go Back</button> </div> <div> <button onClick={handleNavigation}>Go To Different User</button> </div> </div> ); };
In the code block above, two buttons are added to the User
page component: one button to take the user to the previous page and another to navigate the user to a different page. The history.goBack()
method navigates the user to the previous page and goes back one entry in the history stack.
useLocation
The useLocation
Hook allows you to access the location
object that represents the active URL. The value of the location
object changes whenever the user navigates to a new URL.
The useLocation
Hook can be convenient when you have to trigger any event whenever the URL changes.
Consider that you have to keep track of views on users’ profile pages. You can detect changes in the location
object using the useEffect
Hook, which comes with React.
import { // ... useLocation, } from "react-router-dom"; const User = () => { const history = useHistory(); const params = useParams(); const location = useLocation(); useEffect(() => { console.log(location.pathname); // Send request to your server to increment page view count }, [location]); const handleBack = () => { history.goBack(); }; const handleNavigation = () => { history.push("/user/5"); }; return ( <div> <div>This is the user page</div> <div>current user Id - {params.id}</div> <div> <button onClick={handleBack}>Go Back</button> </div> <div> <button onClick={handleNavigation}>Go To Different User</button> </div> </div> ); };
useRouteMatch
The useRouteMatch
Hook matches the active URL with a given path, similarly to how the Route
component works. It’s a very interesting Hook; you can get rid of the unnecessary Route
component and access the match
object.
You can now change the path in the user page’s route component to simply /user
:
<Route path="/user/"> <User /> </Route>
Then, use the routeMatch
Hook, as shown below:
import { // ... useRouteMatch, } from "react-router-dom"; const User = () => { const history = useHistory(); const routeMatch = useRouteMatch("/user/:id"); const location = useLocation(); useEffect(() => { console.log(location); }, [location]); const handleBack = () => { history.goBack(); }; const handleNavigation = () => { history.push("/user/5"); }; return ( <div> <div>This is the user page</div> {routeMatch ? ( <div>user Id - {routeMatch.params.id}</div> ) : ( <div>You are viewing your profile</div> )} <div> <button onClick={handleBack}>Go Back</button> </div> <div> <button onClick={handleNavigation}>Go To Different User</button> </div> </div> ); };
The useParams
hook will not return an empty object since the Route component did not have any route params specified. Instead, you now have access to params in the routeMatch
object.
Conclusion
Hooks are a great addition to the React ecosystem. Now that you’ve seen some code on handling routing with Hooks, you’re ready to take full advantage of what they have to offer.
Until next time, stay safe and keep coding with React Hooks!
Full visibility into production React apps
Debugging React applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.
The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.
Modernize how you debug your React apps — start monitoring for free.
I was following this as a codealong, start is a bit confusing maybe add that the changes are made in App.js.
But I get a compile error at the useEffect() part, until I realized I still had to import it from react.
I’m just 2 weeks in coding in React, so guess for a beginner they will need some more guidance
Did they change something in the ‘react-router-dom’ npm? because it says Switch is not exported from ‘react-router-dom’