circuit

Building an Animated Counter with React and CSS

A guide on how to create your own version of an animated counter component that you come across all over the web


I'll show you how I went about it, but I would love feedback. Is there a better way to do this?

Leave a comment or shoot me an email at jason.melton2@gmail.com.

the code on Github

Preliminary Junk

I set up a create-react-app, deleted a bunch of default stuff, and a file structure like this:

I added some basic CSS to the App component — height, width, and a flex box to center all its contents.

I also set up a json file containing the data that I will map into Count components.

Count Component

The object of my Count component is to accept some data about how the count should run and render the animation.

First, I set up a basic component.

Count gets props of a data item from data.json. I destructured the label, number, and duration from the props.

Using JSX, I return the label and number as a header. Later, I will change number so that it animates, but for now I can style the hard-coded version of what I'm building.

Increment Function

I'm going to set up a function that increments from 0 to the desired number in these three steps.

  1. Set up a useState hook that saves our display number and, when updated, will trigger a render of the component.

The hook looks like this:

I update the JSX to display count instead of number.

  1. Set up a useEffect hook that calculates the count and increment time.

useEffect() firstly takes an anonymous function that will handle the count. I create variables start and end. start is set to 0.

Initially, I used number as my end. However, I realized, for very large numbers, a better method would be use to increment only the first three digits of number and paste the the rest back on before updating the count. This way the counter won't take all night.

I calculate the rate of each increment by dividing the duration (seconds) by the number of increments I plan on doing and multiply by 1000 to convert to milliseconds.

Initially, I was hoping to speed up the interval to make up for large numbers, but setInterval() has a minimum duration of 10 milliseconds. Any number less than 10 will reset back to 10.

  1. In that same useEffect hook, I employ setInterval() to increment the count with side effect of re-rendering the component.

I add one to start and call setCount() to update my useState hook. I convert start to a string and, if it's a large number, I concat the rest of the number that I previously chopped off.

The entire component will now look like this:

Conclusion

I read through several articles about this sort of animation and combined their ideas with my instinct to make the abstract reusable component above.

I am not sure what I came up with is the best method. For example setInterval had limitations I didn't foresee. I would love some feedback. Feel free to shoot me an email at jason.melton2@gmail.com.

Best, Jason




Continue Learning