Build a Timer with React Hooks
Tags: react, javascript
Published: 2020-08-22 12:19:04

In this tutorial, you will learn how to build a timer using react hooks. React hooks is the new way of building react apps and its been available since v16.8.0. More about hooks [here](https://reactjs.org/docs/hooks-intro.html)

> Hooks let you always use functions instead of having to constantly switch between functions, classes, higher-order components, and render props. - [Dan Abramov](https://dev.to/dan_abramov/making-sense-of-react-hooks-2eib)

Let's dive right in.

## Requirements
For this tutorial, you'd need a basic understanding of React and Javascript.

## Getting started 
You can use create-react-app to quickly scaffold a new react app.
```
npx create-react-app react-timer
```

## Building the timer
Create a `Timer.js` component and `style.css` file in the `/src` directory.
```js
import React from 'react';
import './style';

const Timer = () => {
  return (
    <div className="container">
      <div className="time">
        <span className="minute">00</span>
        <span>:</span>
        <span className="second">00</span>
      </div>
      <div className="buttons">
        <button onClick={() => null} className="start">Start</button>
        <button onClick={() => null} className="reset">Reset</button>
      </div>
    </div>
  )
}

export default Timer;
```
This is the barebones Timer component. It has the minute and second values which are hardcoded for now, and two buttons to start and reset the timer. 

### Styles

Add these styles to `style.css` file to make the Timer visually appealing. 😎
```css
.container {
  width: 600px;
  margin: 0 auto;
  display: grid;
  place-items: center;
  margin-top: 5rem;
  background: rgb(66,4,53);
  background: linear-gradient(90deg, rgba(66,4,53,1) 0%, rgba(81,22,111,1) 35%, rgba(12,29,84,1) 100%);
  padding: 3rem 5rem;
  border-radius: 10px;
}

.time {
  font-size: 8rem;
  margin-bottom: 1rem;
  color: white;
}

.buttons button {
  padding: 0.8rem 2rem;
  border: none;
  margin-left: 0.2rem;
  font-size: 1rem;
  cursor: pointer;
  border-radius: 5px;
  font-weight: bold;
  transition: all 300ms ease-in-out;
  transform: translateY(0);
}

.buttons button:hover {
  transform: translateY(-2px);
}


.start {
  background: #3ed927;
  color: white;
}

.pause {
  background: #e4e446;
}

.reset {
  background: #fd7171;
  color: white;
}

```

### Managing State with `useState`
We make our Timer a stateful component by using `useState`.

```js
import React, { useState } from 'react';

const [second, setSecond] = useState('00');
const [minute, setMinute] = useState('00');
const [isActive, setIsActive] = useState(false);
const [counter, setCounter] = useState(0);

const Timer = () => {
  return (
    <div className="container">
      <div className="time">
        <span className="minute">{minute}</span>
        <span>:</span>
        <span className="second">{second}</span>
      </div>
      <div className="buttons">
        <button onClick={() => setActive(true)} className="start">Start</button>
        <button onClick={() => null} className="reset">Reset</button>
      </div>
   </div>
  )
}
```
We now have the `second`, `minute`, `isActive` and `counter` values in state. `isActive` will be used to toggle the active and inactive states of the timer. We start the timer by adding an onClick handler to the start button which sets the `isActive` state to true.

### Adding effects with `useEffect`
To trigger the timer which is a side effect, we need to use `useEffect`.

```js
import React, { useState, useEffect } from 'react';

const [second, setSecond] = useState('00');
const [minute, setMinute] = useState('00');
const [isActive, setIsActive] = useState(false);
const [counter, setCounter] = useState(0);

const Timer = () => {
  useEffect(() => {
    let intervalId;

    if (isActive) {
      intervalId = setInterval(() => {
        const secondCounter = counter % 60;
        const minuteCounter = Math.floor(counter / 60);

        const computedSecond = String(secondCounter).length === 1 ? `0${secondCounter}`: secondCounter;
        const computedMinute = String(minuteCounter).length === 1 ? `0${minuteCounter}`: minuteCounter;
  
        setSecond(computedSecond);
        setMinute(computedMinute);

        setCounter(counter => counter + 1);
      }, 1000)
    }

    return () => clearInterval(intervalId);
  }, [isActive, counter])

  return (
    <div className="container">
      <div className="time">
        <span className="minute">{minute}</span>
        <span>:</span>
        <span className="second">{second}</span>
      </div>
      <div className="buttons">
        <button onClick={() => setIsActive(!isActive)} className="start">
          {isActive ? "Pause": "Start"}
        </button>
        <button onClick={() => null} className="reset">Reset</button>
      </div>
   </div>
  )
}
```
Lets  break down what's going on in the `useEffect`.
- Toggle the start button value(Start or Pause) based on `isActive` state.
- We only run the `setInterval` function if `isActive` is true.
- `secondCounter` is calculated by getting the remainder of counter divided by 60 - using the modulo operator (%).
- `minuteCounter` is calculated by dividing the counter by 60 and rounding it down using `Math.floor`.
- We append an extra zero to the second and minute values so that we always have 2 digits.
- We update the `second` and `minute` states using the `computedMinute` and `computedSecond` values.
- `count` is also increased by 1 every second the effect runs.
- We return a cleanup function to clear the interval when the effect stops running.
- Lastly, we add the `isActive` and `counter` state to the dependency array. This ensures that the effect only runs when either of them changes.

To stop the timer and reset all state values, we add a `stopTimer` function which runs when the reset button is clicked.

```js
import React, { useState, useEffect } from 'react';

 // state values are here ......

  // useEffect runs here .......

const Timer = () => {
  function stopTimer() {
    setIsActive(false);
    setCounter(0);
    setSecond('00');
    setMinute('00')
  }

  return (
    <div className="container">
      <div className="time">
        <span className="minute">{minute}</span>
        <span>:</span>
        <span className="second">{second}</span>
      </div>
      <div className="buttons">
        <button onClick={() => setIsActive(!isActive)} className="start">
          {isActive ? "Pause": "Start"}
        </button>
        <button onClick={stopTimer} className="reset">Reset</button>
      </div>
   </div>
  )
}
```

## Conclusion 
In this article, we learnt how to build a timer using React Hooks. The preview of the finished timer is below. Please like and share.
{% codesandbox cuq74 %}