Search code examples
reactjstypescriptreact-hooksuse-statestopwatch

useState doesn't work first time when given date in string while implementing stop watch


I have uploaded my code here in https://codesandbox.io/s/blissful-lehmann-o4thw?file=/src/Layout.tsx

I am trying to do a stopwatch. But working not as expected due to hook issue.

 const startTimer = async () => {
   setDisableStart(true);
   setDisableStop(false);
   const rightNowTime = await Date.now().toString();
   setCurrentTime(rightNowTime);
   interval = setInterval(() => {
     calculateTime();
   }, 1);
};

I can see problem with setCurrentTime(rightNowTime) is not updating current time

Please, somebody, suggest


Solution

  • You are making things a bit more complicated than they need to be. I suggest storing only a start time and a current "tick" and compute the derived "state" of the minutes, seconds, and milliseconds between these two timestamps.

    const App = () => {
      const [startTime, setStartTime] = useState<number>(0);
      const [currentTime, setCurrentTime] = useState<number>(0);
    
      // Store interval id in React ref
      const intervalRef = useRef<number | undefined>();
    
      const [disableStop, setDisableStop] = useState<boolean>(true);
      const [disableReset, setDisableReset] = useState<boolean>(true);
      const [disableStart, setDisableStart] = useState<boolean>(false);
    
      // Return cleanup function to clear any running intervals
      // on the event of component unmount
      useEffect(() => {
        return () => clearInterval(intervalRef.current);
      }, []);
    
      const calculateTime = () => {
        setCurrentTime(Date.now());
      };
    
      const startTimer = () => {
        setDisableStart(true);
        setDisableStop(false);
    
        // Only update start time if reset to 0
        if (!startTime) {
          setStartTime(Date.now());
        }
    
        // Invoke once immediately
        calculateTime();
    
        // Instantiate interval
        intervalRef.current = setInterval(() => {
          calculateTime();
        }, 1);
      };
    
      const stopTimer = () => { ... };
    
      const resetTimer = () => { ... };
    
      // Compute the minutes, seconds, and milliseconds from time delta
      const delta: number = currentTime - startTime; // in ms
      const minutes: string = Math.floor(delta / (1000 * 60)).toString();
      const seconds: string = (Math.floor(delta / 1000) % 60)
        .toString()
        .padStart(2, "0");
      const milliseconds: string = (delta % 1000).toString().padStart(3, "0");
    
      return (
        <React.Fragment>
          <div className="container">
            <h1>Stop Watch</h1>
          </div>
          <Layout seconds={seconds} minutes={minutes} milliseconds={milliseconds} />
          <Buttons ... />
        </React.Fragment>
      );
    };
    

    Edit usestate-doesnt-work-first-time-when-given-date-in-string-while-implementing-st#70617216