Using the useHistory Hook to Redirect After a Fetch Request in React

David Ryan Morphew
5 min readOct 12, 2021

A Quick How-to with the useHistory Hook

If you are building an SPA (Single Page Application) with React, you probably are going to want to emulate page changes using react-router-dom. If you’re not on board with that, this blog might not be what you’re looking for.

…err, this isn’t the blog you’re looking for … ?

In this blog, I want to highlight how you can use the useHistory hook to redirect after running a fetch request.

React Router Setup

Install and Import Routing

Let’s start with some basics. First, make sure you’ve installed react-router-dom:

npm install react-router-dom

Then, let’s start by importing some basics, like a BrowserRouter, Switch, and Router (I’m doing this in “App.js,” i.e. at the top of my application.):

src/App.jsimport React from 'react';
import {
BrowserRouter as Router,
Switch,
Route
} from 'react-router-dom';
const App = () => {
return(
<>
App goes here
</>
)
}

Building out Routes and Components

Now, for the purposes of this example, let’s suppose

  1. we have an About page and component
  2. we have a component that we’ll use to display our daily-thoughts, called DailyThoughts
  3. we have a component called DailyThoughtForm that we can use to submit data for a new daily-thought
  4. we want to create routes for each of the components we are going to display, one for About, one for DailyThoughts, and one for DailyThoughtForm

we are storing and retrieving the daily-thoughts in an API database

This App’s Components (to Which We’ll Route)

For 1.–3.:

src/App.jsimport React from 'react';
import {
BrowserRouter as Router,
Switch,
Route
} from 'react-router-dom';
import About from './components/About'
import DailyThoughts from './components/DailyThoughts'
import DailyThoughtForm from './components/DailyThoughtForm'
const App = () => {
return(
<>
<About />
<DailyThoughtForm />
<DailyThoughts />
</>
)
}

Adding the Navbar and Links

For 4., let’s add in routes and a Navbar component in a header, too.

src/App.jsimport React from 'react';
import {
BrowserRouter as Router,
Switch,
Route
} from 'react-router-dom';
import About from './components/About'
import DailyThoughts from './components/DailyThoughts'
import DailyThoughtForm from './components/DailyThoughtForm'
import Navbar from './components/Navbar'
const App = () => {
return(
<Router>
<header>

<Navbar />
</header>

<Switch>
<Route exact path="/">
<About />
</Route>
<Route exact path="/dailythoughts/new">
<DailyThoughtForm />
</Route>
<Route exact path="/dailythoughts">
<DailyThoughts />
</Route>
</Switch>
</Router>
)
}

As a quick detour, for our Navbar component:

src/components/Navbar.jsimport { NavLink } from 'react-router-dom'const Navbar = () => { const link = {
padding: '12px',
margin: '0 6px 6px',
background: 'teal',
textDecoration: 'none',
color: 'white',
display: 'flex',
justifyContent: 'center',
flex: 1
}
return(
<div className="navbar">
<NavLink
to="/"
exact
style={link}
activeStyle={{background: "lightgreen", color: "black"}}
>
About
</NavLink>
<NavLink
to="/dailythoughts"
exact
style={link}
activeStyle={{background: "lightgreen", color: "black"}}
>
Daily Thoughts
</NavLink>

<NavLink
to="/dailythoughts/new"
exact
style={link}
activeStyle={{background: "lightgreen", color: "black"}}
>
New Daily Thought
</NavLink>
)
}
  • Now we have a Navbar that directs to each of the different components and emulates a change in webpages.
  • To do this, we use a NavLink and specify the route, which will match the route we have in our App’s Router

Fetching Data and Storing in State with useEffect and useState

For 5., let’s add in a fetch request and state to retrieve all of the daily-thoughts we already have stored in our API database:

src/App.jsimport React, { useState, useEffect } from 'react';
import {
BrowserRouter as Router,
Switch,
Route
} from 'react-router-dom';
import About from './components/About'
import DailyThoughts from './components/DailyThoughts'
import DailyThoughtForm from './components/DailyThoughtForm'
import Navbar from './components/Navbar'
const App = () => { const [dailyThoughts, setDailyThoughts] = useState([])

useEffect(() => {
fetch('https://mythoughtsapi.com/dailythoughts')
.then(resp => resp.json()
.then(returnedDailyThoughts => {
setDailyThoughts(returnedDailyThoughts)
}
}, [])
return(
<Router>
<header>
<Navbar />
</header>

<Switch>
<Route exact path="/">
<About />
</Route>
<Route exact path="/dailythoughts/new">
<DailyThoughtForm />
</Route>
<Route exact path="/dailythoughts">
<DailyThoughts dailyThoughts={dailyThoughts}/>
</Route>
</Switch>
</Router>
)
}
  • Here, the useEffect hook will run after the initial mounting and rendering of App. That’s what the [] second argument in useEffect ensures.
  • We also are setting the returned data of saved daily posts in our component’s state of dailyThoughts, using setDailyThoughts after the data is returned.
  • We then make sure to pass down the dailyThoughts state to the DailyThoughts component, which will display each daily-thought for us.
  useEffect(() => {
fetch('https://mythoughtsapi.com/dailythoughts')
.then(resp => resp.json()
.then(returnedDailyThoughts => {
setDailyThoughts(returnedDailyThoughts)
}
}, [])
...
<DailyThoughts dailyThoughts={dailyThoughts}/>
...

Using the useHistory Hook to Reroute after Fetching

Rerouting City Diagram
Photo by José Martín Ramírez Carrasco on Unsplash

Now we get to the use of the useHistory hook I want to highlight. We can reroute at any point in our app using the useHistory hook. For this example, suppose we want to reroute to the DailyThoughts component upon completion of the fetch request.

src/App.jsimport React, { useState, useEffect } from 'react';
import {
BrowserRouter as Router,
Switch,
Route
} from 'react-router-dom';
import About from './components/About'
import DailyThoughts from './components/DailyThoughts'
import DailyThoughtForm from './components/DailyThoughtForm'
import Navbar from './components/Navbar'
const App = () => { let history = useHistory(); const [dailyThoughts, setDailyThoughts] = useState([])

useEffect(() => {
fetch('https://mythoughtsapi.com/dailythoughts')
.then(resp => resp.json()
.then(returnedDailyThoughts => {
setDailyThoughts(returnedDailyThoughts)
history.push('/dailythoughts')
}
}, [])
return(
<Router>
<header>
<Navbar />
</header>

<Switch>
<Route exact path="/">
<About />
</Route>
<Route exact path="/dailythoughts/new">
<DailyThoughtForm />
</Route>
<Route exact path="/dailythoughts">
<DailyThoughts dailyThoughts={dailyThoughts}/>
</Route>
</Switch>
</Router>
)
}

Set the Variable

  • We first set a variable for the useHistory hook. Here, we can just call it history:
let history = useHistory();

Use the .push Method

  • Then, wherever we want to cause a redirect in our app, whether that is after a fetch request—or after checking something like whether the use is logged in and authorized—we can simply use our variable + the .push(<route>)method to redirect to whatever route we’d like.
  ...
useEffect(() => {
fetch('https://mythoughtsapi.com/dailythoughts')
.then(resp => resp.json()
.then(returnedDailyThoughts => {
setDailyThoughts(returnedDailyThoughts)
history.push('/dailythoughts')
}
}, [])
...
  • Here, we redirect to the '/dailythoughts' route, which will take our user to the the route that displays our <DailyThoughts/> component:
    ...
<Route exact path="/dailythoughts">
<DailyThoughts dailyThoughts={dailyThoughts}/>
</Route>
...

Try it out!

This also works great with React-Redux and Thunk. You can pass your history variable as an argument to an asynchronous action-creator and then use the useHistory hook to redirect after the asynchronous function completes its task.

--

--

David Ryan Morphew

I’m very excited to start a new career in Software Engineering. I love the languages, frameworks, and libraries I’ve already learned / worked with (Ruby, Rails,