Building Dynamic Timers in React Managing State and Effects

Introduction

Timer component and an ExampleComponent. The Timer component features functionality to start a timer upon button click, incrementing every 60 milliseconds while displaying both the count of button clicks and elapsed time. It supports pausing and resetting the timer. The ExampleComponent allows users to dynamically add multiple instances of the Timer component, each managing its own independent state for counting and timing. This setup demonstrates how to manage dynamic component instances and stateful behavior in a React application efficiently.

Code

import React, { useState, useEffect } from 'react';
function Timer() {
  const [count, setCount] = useState(0);
  const [timer, setTimer] = useState(0);
  const [isRunning, setIsRunning] = useState(false);
  useEffect(() => {
    let interval;
    if (isRunning) {
      interval = setInterval(() => {
        setTimer((prevTimer) => prevTimer + 1);
      }, 60);
    } else {
      clearInterval(interval);
    }
    return () => clearInterval(interval);
  }, [isRunning]);
  const increment = () => {
    setCount((prevCount) => prevCount + 1);
    if (!isRunning) {
      setIsRunning(true);
    }
  };
  const reset = () => {
    setCount(0);
    setTimer(0);
    setIsRunning(false);
  };
  return (
    <div style={{ border: '1px solid black', padding: '10px', margin: '10px' }}>
      <p>Count: {count}</p>
      <p>Timer: {timer} seconds</p>
      <button onClick={increment}>{isRunning ? 'Pause' : 'Start'}</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}
function ExampleComponent() {
  const [instances, setInstances] = useState([]);

  const handleAddInstance = () => {
    setInstances((prevInstances) => [...prevInstances, <Timer key={prevInstances.length} />]);
  };
  return (
    <div>
      <button onClick={handleAddInstance}>+</button>
      {instances.map((instance, index) => (
        <div key={index}>{instance}</div>
      ))}
    </div>
  );
}
export default ExampleComponent;

Explanation

  1. useState: count, timer, and isRunning are state variables initialized using the useState hook.
  2. use effect
    • Manages the timer functionality using setInterval when isRunning is true. It increments the timer every 60 milliseconds.
    • It cleans up the interval using clearInterval when isRunning becomes false (component unmount or pause).
  3. Functions
    • increment(): Increments count and start the timer if not already running.
    • reset(): Resets count, timer, and stops the timer.
  4. useState: instances manage an array of Timer components.
  5. handleAddInstance: Adds a new Timer component (<Timer />) to the instances array. Each instance is given a unique key based on the current length of instances.
  6. Rendering
    • Renders a + button to add new instances of Timer.
    • Maps through instances array and renders each Timer component.

Conclusion

How to manage multiple instances of a timer component dynamically in React. Each timer instance maintains its own state (count, timer, isRunning) and can be independently started, paused, or reset. The ExampleComponent showcases how to add new instances of Timer and render them dynamically based on user interaction.