Explanation
We all know it, every web application make API calls, even the tiniest do so. ( Remember that first Todo app you made with a cat API ?).
You’ll gather some data, render it and do whatever you like on the website.. The real problems arises when either your internet is slow, or the data you need to gather is huge.
Imagine if you need to gather that huge amount of data with barely an Edge connection.. It will take a couple of seconds, at least, to get everything from the API endpoint, right ? What if your user go on another page ?
If you thinked :
« Uh - Nothing, it’s not a big deal anyway. At most the data is uploaded and nothing will happen. »
Well.. You are partially right, NOTHING will happen. Thanks to our job, making mistakes is riskless - most of the time at least, but there’s always place for improvement and it’s our duty to free up as much network space as we can, and make our apps less data consuming.
Without forever teasing, let’s dive straight into it.
Cancelling the calls
First, I created a simple app which render only 2 components :
- One who will be responsible to make the API call, and to render a button who will handle the redirection.
- The other component will only render a string.
const App = () => {
const [apiCallDone, setApiCallDone] = useState(false);
return (
<div className="App">
{apiCallDone
? <AnotherComponent />
: <ApiCallComponent redirectToOtherComponent={setApiCallDone} />
}
</div>
);
}
As you can see, once the apiCall will be set as true, App.js will re-render and show the other component.
Now let’s take a look at the component that make the actual call.
const ApiCallComponent = ({ redirectToOtherComponent }) => {
const [result, setResult] = useState([]);
useEffect(() => {
fetch('https://pokeapi.co/api/v2/pokemon/12')
.then(res => res.json())
.then(data => setResult(data))
},[]);
const redirect = () => {
redirectToOtherComponent(true)
};
return (
<button onClick={redirect} > Let's call the APi </button>
)
};
As you can see I reproduce a really simple component, that will make a call to the Pokémon API as soon as it’ll mount. And the button will trigger the function we passed in the props.
Nothing fancy, right ? We literally made a really minimal representation of all our apps - Gather data, consume it, and possibly show a different view / redirect.
Now let’s add some lags into our call by adding a timeout. Doing so we’ll mimic the slow internet.
useEffect(() => {
setTimeout(() => {
fetch('https://pokeapi.co/api/v2/pokemon/12')
.then(res => res.json())
.then(data => setResult(data))
.catch(err => {
// Handle error ..
})
}, 3000);
});
Now let’s try to make our call, and to click on the button within the 3 seconds timer ..
Here’s what we were looking for. And I bet you know what this error is. It means that you’re trying to update a component state while the component was unmounted. In our exemple, it’s literally because we didn’t cancel our api call on the unmount.
Fetch cancel
To fix this with the fetch API :
useEffect(() => {
// First, create a controller, more infos there : https://developer.mozilla.org/en-US/docs/Web/API/AbortController
const controller = new AbortController();
setTimeout(() => {
// Then give it in the fetch options, so the controller is properly linked
fetch('https://pokeapi.co/api/v2/pokemon/12', {signal: controller.signal})
.then(res => res.json())
.then(data => setResult(data))
.catch(err => {
// Handle error ..
})
}, 3000);
// Then on the "unmount" of the component, abort the API call ..
return () => controller.abort();
}, []);
That's all !
Axios
useEffect(() => {
// More informations about the cancelation for the axios library here : https://github.com/axios/axios#cancellation
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
setTimeout(() => {
axios('https://pokeapi.co/api/v2/pokemon/12', { cancelToken: source.token })
.then((res) => setResult(res.data) )
.catch((err) => {
// Handle error..
} )
}, 3000);
return () => source.cancel();
}, []);
Congratulation ! You’ve now cleared your console from this filthy errors !
No more excuses when you'll create an API call, you now have all the tools to handle it properly.
You can find the original article on the Othrys website and you can follow my Twitter or tag me here to discuss about this article.
Have a nice day !
Top comments (4)
Nice Article Axel, I didn't know there was an AbortController option
Thanks, really cool and simple.
Using network slow network emulation also do the trick without adding a timeout to your code
Very true, I must use that more often. Thanks for the tip