Creating a dynamic counter with Start, Pause and Reset button functionality using React

During my recent job search, I encountered this question multiple times, posed by interviewers from reputable companies such as FlexCar and BetterHalf. It underscores the importance of understanding custom hooks, state management and component composition in React interviews.

we’ll walk through the process of building a counter that not only displays the current count but also provides the functionality to start, pause, and reset it. We’ll focus on modularity and encapsulation, breaking down our components into smaller, reusable parts. By the end of this tutorial, you’ll have a deeper understanding of structuring components and hooks for enhanced maintainability and flexibility.

To achieve modularity, we’ll break down our Counter component into smaller, reusable parts. Let’s start with the custom hook responsible for managing the counter state and actions.

// Custom hook for managing counter state and actions
import { useState, useEffect } from 'react';

const useCounterHook = () => {
  // State variables for count and running state
  const [count, setCount] = useState(0);
  const [isRunning, setIsRunning] = useState(false);

  // Functions to handle start, pause, and reset actions
  const handleStart = () => {
    setIsRunning(true);
  };

  const handlePause = () => {
    setIsRunning(false);
  };

  const handleReset = () => {
    setCount(0);
    setIsRunning(false);
  };

  // Effect for updating count based on running state
  useEffect(() => {
    let intervalId;

    if (isRunning) {
      intervalId = setInterval(() => {
        setCount(prevCount => prevCount + 1);
      }, 1000);
    } else {
      clearInterval(intervalId);
    }

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

  // Return state variables and action functions
  return { count, handleStart, handlePause, handleReset };
};

export default useCounterHook;


In the above custom hook, we have exposed the count and method to start, pause and reset the count. We will use these exposed values in the main component as below.

import React, { useState } from "react";
import "./styles.css";
import useCounterHook from "./useCounterHook";

const App = () => {
  const { count, handleStart, handlePause, handleReset } = useCounterHook();

  return (
    <div className="counter">
      <div className="counter">{count}</div>
      <button onClick={handleStart}>Play</button>
      <button onClick={handlePause}>Pause</button>
      <button onClick={handleReset}>Reset</button>
    </div>
  );
};
export default App;
  • We use the useState hook to maintain the count state and a boolean flag (isRunning) to track whether the counter is running or paused. Here, we can use “useRef” for storing the ‘isRunning’ flag to avoid unnecessary re-renders.
  • The handleStart, handlePause and handleReset functions update the state based on user interactions.
  • Inside the useEffect hook, we set up an interval to increment the count every second when the counter is running. We clear the interval when the counter is paused or reset.

This is how the components work with start, pause and reset functionality.

1 comment