Skip to content

Instantly share code, notes, and snippets.

@tsmx
Last active May 2, 2021 18:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tsmx/6f01b86bb9ed517b40d161af686ee20b to your computer and use it in GitHub Desktop.
Save tsmx/6f01b86bb9ed517b40d161af686ee20b to your computer and use it in GitHub Desktop.
Counter: a simple React component for animated counting up

Counter: React component for animated counting up

Small React component for counting numbers up to a certain value in a specified duration in ms. Useful for creating animated dashboards etc.

Usage

<Counter countFrom={0} countTo={123} durationMs={400}/>

Code

import React from 'react';

class Counter extends React.Component {

  constructor(props) {
    super(props);
    this.range = props.countTo - props.countFrom;
    this.state = { currentValue: props.countFrom };
  }

  componentDidMount() {
    // no timer shorter than 50ms (not really visible any way)
    const minTimer = 50;
    // calc step time to show all interediate values
    let stepTime = Math.abs(Math.floor(this.props.durationMs / this.range));
    // never go below minTimer
    stepTime = Math.max(stepTime, minTimer);
    // get current time and calculate desired end time
    const startTime = new Date().getTime();
    this.endTime = startTime + this.props.durationMs;
    this.timer = setInterval(() => {
      this.countUp();
    }, stepTime);
    this.countUp();
  }

  componentWillUnmount() {
    if (this.timer) {
      clearInterval(this.timer);
    }
  }

  countUp() {
    const now = new Date().getTime();
    const remaining = Math.max((this.endTime - now) / this.props.durationMs, 0);
    const value = Math.round(this.props.countTo - remaining * this.range);
    this.setState({ currentValue: value });
    if (value === this.props.countTo) {
      clearInterval(this.timer);
      this.timer = null;
    }
  }

  render() {
    return <span>{this.state.currentValue}</span>;
  }
}

Counter.defaultProps = {
  durationMs: 400
};

export default Counter;

For an equivalent functional React component implementation see here.

Example

Try it out on CodeSandbox.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment