Optimize API calls via Axios' CancelToken

Every product has its search bar, and there are two ways in which you can implement it. In the first use case scenario, you let the people type what they want to search and ask them to click submit/search button at the end.
Secondly, Like google suggestion, hashnode search bar, you show the possible results/suggestion based on every character enter by a user. Of course, it will add extra load onto the server, but you will provide a good user experience.
SO, Is there is any way in which we can reduce the load onto the server? Yes, By using Axios' CancelToken, if a user sends a new request before the previous one gets fulfilled, an older one will get cancelled and removed from the pipeline and a new request will be executed, without giving extra load onto a server
How? Don't worry, I am here to explain you.
Step #0 Setting up a React Project โ๏ธ
We will create a simple React application using create-react-app or you can use any online editor like Stackblitz, Codesandbox etc. After creating react app, also install bootstrap, reactstrap, Axios package using command
npm install bootstrap reactstrap axios
Step #1 Create simple Input-Search bar ๐ and User Card
Now, create a basic input search bar inside SearchBar.js (React functional component), saving the input value in a state
import React, { Fragment, useState } from 'react'
import 'bootstrap/dist/css/bootstrap.min.css'
import './App.css';
import SearchBar from './Component/SearchBar';
const App = () => {
const [username,setUser] = useState("mayur-keswani")
return (
<Fragment>
<SearchBar username={username} changed={(event)=>setUser(event.target.value)}/>
</Fragment>
);
}
import React, { Fragment } from 'react'
import './SearchBar.css'
const SearchBar = (props) =>{
return(
<div className="form-group mx-auto mt-5 search-tab" style={{width:"80%"}}>
<input type="text"
className="form-control"
placeholder="Enter username"
value={props.username}
onChange={props.changed}
/>
</div>
)
}
export default SearchBar
Now pass the input value entered by the user as a prop to the UserDetails component. And display the value using the card utility component of reactstrap
import React, { Fragment, useEffect, useState } from 'react'
import {
Card,
CardText,
CardBody,
CardLink,
CardTitle,
CardSubtitle } from 'reactstrap';
const UserInfo = ({username}) =>{
const [userDetails,setUserDetails] = useState({});
return(
<Card className="mx-auto bg-secondary" style={{width:"50%"}}>
<CardBody>
<CardTitle tag="h5">{username}</CardTitle>
<CardSubtitle tag="h6">(Searched User)</CardSubtitle>
</CardBody>
</Card>
)
}
export default UserInfo;
Pretty Simple, Right?
Step #2 Getting details of searched User ๐ฅ
We will be using Github API to fetch publicly available information of a user. Click the following link,
https://api.github.com/users/mayur-keswani
This is an API endpoint that GitHub has provided that return information for a specified user in JSON format. You can dynamically pass in the GitHub username that we'd like to request info for.
If your JSON isn't nicely formatted, I highly recommend you download the free JSONView Chrome Extension.
Let's take the username props that we're passing into our function and use that dynamically within the GitHub API endpoint.
`https://api.github.com/users/${username}`
const UserInfo = ({username}) =>{
const [userDetails,setUserDetails] = useState({});
const fetchUser = async()=>{
axios.get(`https://api.github.com/users/${username}`)
.then(res=>{
setUserDetails(res.data)
})
.catch(err=>{
setUserDetails(null)
console.log(err.message)
})
}
useEffect(()=>{
fetchUser()
},[username])
return(
<Card className="mx-2 bg-light" >
{
userDetails?
(
<>
<CardBody>
<CardTitle tag="h3" className="mx-1">{userDetails.name}</CardTitle>
<CardSubtitle tag="h6" className="mx-2 text-muted">Type :{userDetails.type}</CardSubtitle>
</CardBody>
<img className="img-thumbnail mx-1"
width="200px"
height="50%"
src={userDetails.avatar_url}
alt="avatar" />
<CardBody className="mx-1">
<CardText>{userDetails.bio}</CardText>
<CardText> Hireable :{userDetails.hireable?" YES":" NO"}</CardText>
<CardText>Location : {userDetails.location}</CardText>
<CardLink href={userDetails.repos_url}>Repos URL</CardLink>
</CardBody>
</>
):
(
<CardBody>
<CardTitle tag="h5" className="text-danger">Not Found</CardTitle>
<CardSubtitle tag="h6">(Searched User)</CardSubtitle>
</CardBody>
)
}
</Card>
)
}
After running the code above, you will get a response with status code 200 (successful) and an object containing information about a searched user. Store this information on state and render it using the Card utility of reactstrap. From here you can certainly put your own spin on things and truly make them your own.
In case, if there is no such user with this name, you will get a response with status code 404 (Not Found) and an object containing an error message.

Step #3 Cancelling previous request
With every new character entered by the user, a request is being sent to GitHub API. By the time it gets fulfilled, a new request is being made.
In order to cancel the previous request, we need to pass the cancel token as a config with every Axios request and call the cancel() function whenever we need to cancel the previous Axios request.
You can create a cancel token using the CancelToken.source factory as shown below:
useEffect(()=>{
const CancelToken=axios.CancelToken.source()
fetchUser(CancelToken)
return ()=>{
CancelToken.cancel(`Previous Request Cancelled @${username}`)
}
},[username])
const fetchUser = async(CancelToken)=>{
axios.get(`https://api.github.com/users/${username}`,{
cancelToken:CancelToken.token
})
.then(res=>{
setUserDetails(res.data)
})
.catch(err=>{
setUserDetails(null)
console.log(err.message)
})
}
We can use the same cancel token for multiple Axios requests.
Awesome! ๐๐
Surely. you can use a debouncing or custom function that waits for some time (maybe some hundred milliseconds) before firing the API call and making the request only after the said amount of time interval from the last on-change event. In this way, we reduce the network conjunction and reduce the number of requests to the backend.
But, the Use case here is to cancel the previous request.
Source Code : Repo Link
Reference
๐ GITHUB API Documentation : https://docs.github.com/en/rest/overview/resources-in-the-rest-api
๐ Axios : https://github.com/axios/axios#cancellation
I keep writing about the things I learned and applied. So you can connect with me on Twitter, Github. Also, subscribe to my newsletter and stay up-to-date with my latest blog posts.
Keep Learning!โก