Using the useHistory Hook to Redirect After a Fetch Request in React
--
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.
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
- we have an
About
page and component - we have a component that we’ll use to display our daily-thoughts, called
DailyThoughts
- we have a component called
DailyThoughtForm
that we can use to submit data for a new daily-thought - we want to create routes for each of the components we are going to display, one for
About
, one forDailyThoughts
, and one forDailyThoughtForm
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 inuseEffect
ensures. - We also are setting the returned data of saved daily posts in our component’s state of
dailyThoughts
, usingsetDailyThoughts
after the data is returned. - We then make sure to pass down the
dailyThoughts
state to theDailyThoughts
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
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 ithistory
:
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.