Search code examples
reactjstsx

why my react simple timer project doesn't work?


I'm trying to code a simple timer with two buttons. Start Button: timer will be added by one every 10ms. Lap Button: timer will be pushed to an array and also showed in a pre tag. Unfortunately, Lap Button doesn't work. can anybody help me figure this issue out? TY.

import { useState } from "react";
import { formatSeconds } from "./format";
let interval : NodeJS.Timer;

function App() {
  const [buttonName, setButtonName] = useState("Start");
  let [timer, setTimer] = useState(0);
  const laps : Array<number> = [];

  const handleStartClick = () => {
    setButtonName(buttonName === "Start" ? "Stop" : "Start")

    if(buttonName === "Start"){
      interval = setInterval(() => {
        setTimer(timer += 1)
      }, 10);
    }else{
      clearInterval(interval)
    }
    
  }

  const handleLapClick = () => {
    laps.push(timer);
  }

  return (
    <div>
      <button onClick={handleStartClick}>{buttonName}</button>
      <button onClick={handleLapClick}>Lap</button>
      <div>
        <p>Elapsed:</p> <pre id="elapsed">{formatSeconds(timer)}</pre>
      </div>
      <hr />
      <div id="laps">
        <p>Laps:</p>
        {laps?.map((item) => {
          return <pre key={item}>{formatSeconds(item)}</pre>;
        })}
      </div>
    </div>
  );
}

export default App;

   

Solution

  • Problem:: Your component is not updating on handleLapClick function.

    Solution:

    • Change laps to a state variable using the useState hook
    • Instead of pushing values to the laps array, update the laps state by creating a new array that includes the current timer value.

    (The reason behind creating a new array and then updating the laps state is because of a concept called, state immutability in React)

    Changes to be made:

    const [laps, setLaps] = useState<number[]>([]);
    
    const handleLapClick = () => {
        setLaps((prevLaps) => [...prevLaps, timer]);
      };
    

    Correct code after making changes:

    import { useState } from "react";
    import { formatSeconds } from "./format";
    
    let interval: NodeJS.Timer;
    
    function App() {
      const [buttonName, setButtonName] = useState("Start");
      const [timer, setTimer] = useState(0);
      const [laps, setLaps] = useState<number[]>([]);
    
      const handleStartClick = () => {
        setButtonName((prevButtonName) =>
          prevButtonName === "Start" ? "Stop" : "Start"
        );
    
        if (buttonName === "Start") {
          interval = setInterval(() => {
            setTimer((prevTimer) => prevTimer + 1);
          }, 10);
        } else {
          clearInterval(interval);
        }
      };
    
      const handleLapClick = () => {
        setLaps((prevLaps) => [...prevLaps, timer]);
      };
    
      return (
        <div>
          <button onClick={handleStartClick}>{buttonName}</button>
          <button onClick={handleLapClick}>Lap</button>
          <div>
            <p>Elapsed:</p> <pre id="elapsed">{formatSeconds(timer)}</pre>
          </div>
          <hr />
          <div id="laps">
            <p>Laps:</p>
            {laps.map((item, index) => (
              <pre key={index}>{formatSeconds(item)}</pre>
            ))}
          </div>
        </div>
      );
    }
    
    export default App;