Sometime’s there’s a need to add a simple component in your react application that can be used for adding an animated counter.

In order to first create this component, we need to install Create-react-app as a boilerplate for our component, if you already have set up then you can ignore this.

You may also like.

Installing the boilerplate.

npx create-react-app counter
cd counter
npm start

then create a new file named as Counter.js and Counter.css

React Counter Component

How Animated Counter Component in React works?

In order to achieve the counting system, we add an onClick() function which gets launched whenever we click the +1 or -1 button. And then this +1 or -1 gets appended to handleValueChange() function. Anyways let’s look into the source code to see how it works.

Source Code for Animated Counter Component.

in Counter.js add these lines to create a component.

First, open the App.Js file in your text editor, and remove everything from the div other than the first tag. Make the central div look like this.

<div id="app"></app>

Then import the component below in order to make it render there in the main div. It should be on the top, just below the Import React line.

import Counter from './Counter.js';
import React from 'react';
import './Counter.css';


class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.inputRef = React.createRef()
    this.state = { curValue: 1 }
  }
  
  changeValue = ({curValue, newValue}) => {
    this.setState({ curValue: newValue !== 100 ? newValue : 99 })
  }
  
  handleValueChange = (newValue, isField) => {
    const {
      props: { id, onChange },
      state: {
        curValue
      }
    } = this

    newValue = parseInt(newValue, 10)

    if (!newValue) {
      if (isField) {
        newValue = ''
      } else {
        newValue = 1
      }
    }
    if (newValue < 0) {
      newValue = 1
    }
    if (!isField) {      
      this.inputRef.current.style.transform = newValue > curValue ? 'translateY(-100%)' : 'translateY(100%)'
      this.inputRef.current.style.opacity = 0
       
    setTimeout(() => {
        this.inputRef.current.style.transitionDuration = '0s'
        this.inputRef.current.style.transform = newValue > curValue ? 'translateY(100%)' : 'translateY(-100%)'
        this.inputRef.current.style.opacity = 0
        this.changeValue({ curValue, newValue })
        
        setTimeout(() => {
          this.inputRef.current.style.transitionDuration = '0.3s'
          this.inputRef.current.style.transform = 'translateY(0)'
          this.inputRef.current.style.opacity = 1
        }, 20)
      }, 250)
    } else {
      this.changeValue({ curValue, newValue })
    }    
  }

  render () {
    const {
      state: {
        curValue
      }
    } = this
    
    return (
      <div {...{ className: 'counter' }}>
        <button
          {...{
            className: 'button',
            onClick: () => { this.handleValueChange(curValue - 1) },
            title: '-1'
          }}
        >
          −
        </button>
        <div {...{ className: 'input-wrapper' }}>
          <input
          {...{
            className: 'input',
            maxlength: 2,
            onChange: e => {
              e.preventDefault()
              this.handleValueChange(e.target.value, true)
            },
            ref: this.inputRef,
            type: 'text',
            value: curValue
          }} 
        />
        </div>
        <button
          {...{
            className: 'button',
            onClick: () => { this.handleValueChange(curValue + 1) },
            title: '+1'
          }}
        >
          +
        </button>
      </div>
    )
  }
}

ReactDOM.render(<Counter />, document.getElementById('app'));

Now here’s the stylesheet file Counter.CSS. Since we’ve already imported it there in our component, just create it and add the required code, it’ll automatically start applying the styles.

html {
  font-size: 24px;
}

html,
body {
  height: 100%;
}

body {
  background: #fff;
  display: flex;
  justify-content: center;
  align-items: center;
  font-family: "Open Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}

.counter {
  display: flex;
  align-items: center;
}

.input-wrapper {
  width: 4rem;
  height: 4rem;
  border-radius: 0.6rem/0.8rem;
  background-color: #392342;
  overflow: hidden;
  box-shadow: inset 0 0 0.8rem 0.1rem rgba(0, 0, 0, 0.2), 0 20px 30px -10px rgba(0, 0, 0, 0.26);
}

.input {
  height: 100%;
  width: 100%;
  background: none;
  border: none;
  text-align: center;
  color: #fff;
  font-weight: 900;
  font-size: 2rem;
  outline: none;
  transition-property: transform, opacity;
  text-transform: linear;
  transition-duration: 0.25s;
}

.button {
  background: none;
  border: none;
  padding: 0.8rem;
  color: rgba(57, 35, 66, 0.35);
  font-size: 1.6rem;
  outline: none;
  cursor: pointer;
  transition: color 0.2s ease-in-out;
}
.button:hover {
  color: #392342;
}

You can check out the working code below for animated counter component-

See the Pen Counter react component with animation by Kamran Tahir (@Mah3svara) on CodePen.

unsplash-logoDjim Loic
0 CommentsClose Comments

Leave a comment