If you're reading this, maybe you've been in a situation where you're making a react form where you hit an API when you type in the search box, but the downside is when you type 'batman', the axios made 6 different requests which is 'b', 'ba', 'bat', 'batm', 'batma', and the actual query we're looking for, 'batman'. I hope this article works for you. Let's get started!
Assuming you've initialized the react app by using:
npx create-react-app .
and installed axios by using:
npm i axios
Let's start with initial code in app.js
, we'll make a book search feature:
import './App.css';
function App() {
return (
<div className="App">
<input type="text" />
<div>Result</div>
<div>Loading...</div>
<div>Error</div>
</div>
);
}
Inside the default App
div, we put a text input
and three different div
s, each for result, loading, and error.
Now we create our states by importing useState
and useEffect
:
import { useState, useEffect } from 'react'
and define our book states at the beginning of the App function (before return):
const [query, setQuery] = useState('')
const [loading, setLoading] = useState(true)
const [error, setError] = useState(true)
const [books, setBooks] = useState([])
Then we'll create the axios request in the useEffect
hook:
useEffect(() => {
setLoading(true)
axios({
method: 'get',
url: 'http://openlibrary.org/search.json',
params: { q: query }
})
.then(response => {
let data = response.data.docs.map(book => book.title)
console.log({ query, data })
setBooks(data)
setLoading(false)
})
.catch(err => {
setError(err)
setLoading(false)
})
}, [query])
We set the loading
value with true
to indicate that the axios is sending a request to the url, and set it to false after we get either result. And we set the books
value with only their title if it succeeded, and set the error
if it failed.
Then we 'rework' the three div
s like this:
{
books.map((book, index) => {
return <div key={book}>{ book }</div>
})
}
{
loading &&
<div>Loading..</div>
}
{
error &&
<div>Error</div>
}
And after you run it by using:
npm run start
and type 'batman', it should look like this:
Notice the queries were finished in an order we don't want, so the most recent query we'll get is the query 'b' instead of 'batman'. So now we'll make it so the axios only take the last change made in the input, which is 'batman'.
axios.CancelToken
Actually axios has an option called cancelToken
that can be used to cancel the request. How do we do that? By putting it to the option when we make a request:
useEffect(() => {
let cancel;
console.log('axios called')
axios({
method: 'get',
url: 'http://openlibrary.org/search.json',
params: { q: query },
cancelToken: new axios.CancelToken(c => cancel = c)
})
.then(...)
.catch(...)
return () => cancel()
})
The cancel
variable will then hold the cancel function from axios.CancelToken
, and will be called in useEffect callback return so axios will be cancelled once another useEffect is triggered.
Now we can test it out by running:
npm run start
And type 'batman' in our search box, we'll only get one request
Notice that axios was called 6 times, but only 'batman' request was sent, because the 'b', 'ba', 'bat', 'batm', 'batma' requests are cancelled.
Lastly, we'll get an error for every request cancellation, but because that is intended we can filter the error out by adding conditional in our catch block:
.catch(err => {
if (axios.isCancel(err)) return
...
})
source:
Web Dev Simplified
https://www.youtube.com/watch?v=NZKUirTtxcg
Axios Documentation
https://github.com/axios/axios
Top comments (0)