The web application my development team is building at work provides a lot of data to our users, including downloadable Excel spreadsheets that can sometimes contain up to 250,000 rows’ worth of information. And our users have the ability to generate these reports, on demand, from our tool.
As you may imagine, it can sometimes take several minutes or more to compile this much data, and waiting around looking at a loading animation while our report service crunches numbers in the background wouldn’t be a great user experience.
Instead, we needed a way to check when the report service was done generating a report, without blocking a user from doing other work in our application while that was going on. We needed polling.
Sometimes when building web applications, you’re going to need to keep track of data being created or updated asynchronously by another service. Polling, is one way to accomplish this, and all it is, is simply hitting an API’s endpoint to retrieve any new data at a set interval of time.
This is exactly the type of solution my team needed to implement — a way to periodically keep checking if the reports (being generated by our separate report service) were done, so they could be displayed in the UI for our users to download once they were. And we needed a solution that would work for React.
Today, I’ll be sharing how easy it is to leverage a custom React Hook called
useInterval, to poll an API within your application for fresh data (or really run any task that needs intervals).
Polling VS Webhooks
An alternative to polling is webhooks. Webhooks are a common way for one app to notify of an event, in real-time, to another app.
Webhooks are often referred to as “reverse APIs” because the app consuming the data does not do so by sending an HTTP request to another API — instead, it makes an API available for the app sending the data (usually, a POST HTTP request).
Example: Getting notified when a new component is available
Let’s say one of your teammates has published a component to your shared component collection. You might want to use it in your current project but how would you know that it’s now available?
One way would be by polling.
Another, more elegant and efficient way, would be by using webhooks.
Why am I telling you about webhooks in a post about polling? Well, it’s something to keep in mind when you’re building a solution for a problem that’s potentially solved by both techniques. It may very well be that you don’t actually have an option and polling is the only available solution but if that’s not the case, you should at least consider webhooks.
Intervals from React Classes to React Hooks
Before I dive into the custom useInterval Hook, let me briefly review how polling at intervals used to work in React when we could only use class-based components to work with our state.
SetInterval: The Old Way to Poll in React Classes
Back in the days when we used to be restricted to class-based components for state changes, polling was typically started on the
componentDidMount() lifecycle method as soon as the component was mounted in the DOM. And as long as the component stayed mounted, the
setInterval() function would continue indefinitely. Upon unmounting the component with
componentWillUnmount(), the interval will be cleared and stop running with
clearInterval(). Here’s an example of that code below.
A simple example of how polling intervals used to work in React.
In the example above, I just have the
pollingCount state updating every 3 seconds, as determined by the
delay, which is currently set to 3000ms.
When the component mounts, the
setInterval() starts running, and every 3 seconds it increments the
pollingCount’s state by 1 by calling the
tick() function, which actually updates the state. Once the
PollingExample component unmounts from the DOM, the
clearInterval() function is called and the interval stops running.
This works fine, but if multiple components need intervals to poll for different data or execute other tasks on an interval, there can be a lot of redundant, interval-related code scattered among the components.
Setting up a running interval is pretty simple, but now that we’ve got React Hooks there’s an even simpler, cleaner way to encapsulate polling data into a custom Hook.
UseInterval: The New Way to Poll with React Hooks
When React Hooks first came out, people were critical that
setInterval() didn’t work with Hooks the way that it had with React’s class-based components.
And it’s true, it doesn’t. Dan Abramov wrote a very in-depth explanation of why this is the case (and does a fantastic job of explaining it, so I’ll continue to leave that to him). But in addition to demystifying how
setInterval() works with React’s lifecycles like
componentDidMount(), he also introduced the new Hooks-way of correctly writing intervals to work in function-based React components.
He introduced a new custom hook called
useInterval, and it’s awesome, easy to use, and just what my team needed. Here’s the code for the Hook, taken just as Dan wrote it, and added right to my team’s project in our
The useInterval Hook
The code for the custom useInterval Hook, just as Dan Abramov wrote it.
useInterval Hook sets up an interval and clears it after the component unmounts. It’s a combo of
clearInterval(), but all wrapped into one easy-to-implement Hook.
All you need to do to get the Hook to work is supply it a function (the
callback parameter) and an interval time (the
With this Hook, more than half the battle is already over, now you’re ready to drop this interval Hook wherever you need it in your code. For me and my team, that happened to be in the reports page.
Putting useInterval to Use
Here’s a condensed version of my
ReportsPage functional component with the
useInterval Hook imported at the top of the component and dropped into the code.
Instead of managing multiple component lifecycles, the useInterval hook encapsulates all the interval logic into itself, making it easy to reuse in many places in the code.
In my component, the
useInterval Hook takes in an asynchronous call to fetch any reports that have been generated the by the report service (
reportService.getGeneratedReports()), and then it updates the reports available for download in the UI with
For ease-of-updating the interval timing if need be, I’m using a constant called
REPORT_REFRESH_INTERVAL, which is set to run this polling interval every 15 seconds while the component is mounted.
I added the
console.log so it’s easier to tell if the interval is running correctly.
Inelegant? Maybe. Confirms it’s running on an interval? Sure does.
The count of 11 ahead of the logged message
"Checking if reports are ready to download" demonstrates that the
useInterval Hook is firing at regular intervals while users are on the Report page. If you checked the Network panel right now in the Developer Tools, you’d also see 11 individual API calls to the
getGeneratedReports() REST endpoint.
Once the user navigates to a different page or component, you’ll see the API calls cease with no extra code on my part. Only if the user returns to the Reports page will the polling for reports resume.
How simple is that? Instead of having to write multiple instances of
clearInterval() inside of your class-based components’ lifecycles when you need intervals, you can have one
useInterval Hook that can drop into any functional component anywhere in the app that you need polling.
Now that’s how you poll efficiently with a custom React Hook. And you could use this very same Hook anywhere in your code that an interval is needed.
Sometimes you need a simple way to check if an asynchronous task being performed by a separate service is done or not. Polling is one way to do this; hitting an endpoint over and over at some set interval to check for fresh data to display in the UI.
With the introduction of React Hooks, and especially the ability to put together custom Hooks, creating a reusable Hook called
useInterval to serve just such a purpose seemed inevitable. Dan Abramov, part of the React core team, obliged, and the real beauty of it is, this Hook is highly reusable. It can be dropped anywhere in the app, to run any sort of task, at any interval with next to no effort. That’s the kind of solution I like.
Thanks for reading. If you need intervals in your React app and you’re using Hooks, consider adding this
useInterval Hook to your arsenal, it’s a cinch to use and easy to customize to your specific needs.
If you enjoyed reading this, you may also enjoy some of my other free pieces:
- “Animating React with React Transition Group”
References and Further Resources
- Dan Abramov’s blog post on Overreacted “Making setInterval Declarative with React Hooks”
Asayer is a frontend monitoring tool that replays everything your users do and shows how your web app behaves for every issue. It lets you reproduce issues, aggregate JS errors and monitor your web app’s performance.
Happy debugging, for modern frontend teams - Start monitoring your web app for free.