<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Sagar Sharma</title>
    <description>The latest articles on Forem by Sagar Sharma (@sagar_sharma_2809).</description>
    <link>https://forem.com/sagar_sharma_2809</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1499034%2F5a240ed3-7a3d-41b4-968f-164ebee85dda.jpg</url>
      <title>Forem: Sagar Sharma</title>
      <link>https://forem.com/sagar_sharma_2809</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sagar_sharma_2809"/>
    <language>en</language>
    <item>
      <title>How to build a Stopwatch in React</title>
      <dc:creator>Sagar Sharma</dc:creator>
      <pubDate>Tue, 23 Jul 2024 07:26:29 +0000</pubDate>
      <link>https://forem.com/sagar_sharma_2809/how-to-build-a-stopwatch-in-react-1063</link>
      <guid>https://forem.com/sagar_sharma_2809/how-to-build-a-stopwatch-in-react-1063</guid>
      <description>&lt;p&gt;Hi there, Let's understand how a stopwatch is built in React. This is a beginners guide. &lt;/p&gt;

&lt;h2&gt;
  
  
  Build basic Setup
&lt;/h2&gt;

&lt;p&gt;I am using vite for creating react project as its fast and efficient.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm create vite@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, in your project folder, create a new component Stopwatch.jsx. It's a simple project so we don't need to divide our components much. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F13kl7skindh34q48jpcc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F13kl7skindh34q48jpcc.png" alt="stopwatch component" width="276" height="36"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, move into your component file and write the basic setup. We will need three things now - element to show time, start button, stop button.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default function Stopwatch() {
    return (
        &amp;lt;&amp;gt;
            &amp;lt;h2&amp;gt;Stopwatch count&amp;lt;/h2&amp;gt;
            &amp;lt;button&amp;gt;Start&amp;lt;/button&amp;gt;
            &amp;lt;button&amp;gt;Stop&amp;lt;/button&amp;gt;
        &amp;lt;/&amp;gt;
    )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting State to track current time
&lt;/h2&gt;

&lt;p&gt;We have to set state to track the elapsed time (eg- in seconds) and a boolean state to track if the stopwatch is running or not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState } from "react"

export default function Stopwatch() {

    const [current, setCurrentTime] = useState(0);
    const [isRunning, setIsRunning] = useState(false);

    return (
        &amp;lt;&amp;gt;
            &amp;lt;h2&amp;gt;Stopwatch count&amp;lt;/h2&amp;gt;
            &amp;lt;button&amp;gt;Start&amp;lt;/button&amp;gt;
            &amp;lt;button&amp;gt;Stop&amp;lt;/button&amp;gt;
        &amp;lt;/&amp;gt;
    )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Starting the Stopwatch
&lt;/h2&gt;

&lt;p&gt;Our main functions will be Start, Stop and Reset. Let's first code the start function. &lt;/p&gt;

&lt;p&gt;We will add onClick function to the start button.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;button onClick={start}&amp;gt;Start&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next, let's create the start function, now we want this function to only work when the stopwatch is off/ not running.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const start = () =&amp;gt; {

        if (!isRunning) {

        }

        setIsRunning(true);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will set the stopwatch running after the timer has started. Now, the main function is to increment the time in every specific time. We are incrementing in every 10 milliseconds in this stopwatch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let intervalID = 0;  //we are storing the setInterval() to later clear it while stopping

const start = () =&amp;gt; {

        if (!isRunning) {
            intervalID = setInterval(() =&amp;gt; {
                setCurrentTime((prevTime) =&amp;gt; {
                    return prevTime + 10;
                })
            }, 10)
        }

        setIsRunning(true);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In every 10 ms, we are updating the currentTime state. ( You can also update in every 1000ms i.e - 1 second ).&lt;/p&gt;

&lt;h2&gt;
  
  
  Stopping the Stopwatch
&lt;/h2&gt;

&lt;p&gt;Similar to above &lt;strong&gt;start&lt;/strong&gt; function, we will add a &lt;strong&gt;stop&lt;/strong&gt; function to an onClick function on Stop button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbhpc6dymz2pnss9cmp19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbhpc6dymz2pnss9cmp19.png" alt="stopping button" width="456" height="34"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, our stop function will only work if the stopwatch is running.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const stop = () =&amp;gt; {
        if (isRunning) {
            clearInterval(intervalID);
            setIsRunning(false);
        }

    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, we are also setting the isRunning to false, why? because in the start function, we have mentioned the condition that it will only work if stopwatch is not running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reset the Stopwatch
&lt;/h2&gt;

&lt;p&gt;It's similar to stop function, the only difference is that here we will set the current time to 0 to render the reset of stopwatch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const reset = () =&amp;gt; {
        clearInterval(intervalID);
        setCurrentTime(0);
        setIsRunning(false);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  But, there is a problem
&lt;/h2&gt;

&lt;p&gt;Great, the stopwatch is complete 90%! But, there is an underlying problem with the above code.&lt;/p&gt;

&lt;p&gt;We are storing the intervalID in local variable. The issue with local variables is that they don't survive re-renders. What I mean by that is if our component re-renders due to any state update in future then the local variables are reinitialized.&lt;/p&gt;

&lt;p&gt;IntervalID will be reinitialized everytime the state changes and component re-renders and react wouldn't keep reference to stop when we try to clearInterval. &lt;/p&gt;

&lt;p&gt;So, if we want our component to handle complex states in future without losing the reference to IntervalID, we have to store it in reference variable. Here comes the useRef Hook.&lt;/p&gt;

&lt;h2&gt;
  
  
  useRef Hook
&lt;/h2&gt;

&lt;p&gt;In simple language, its a secret pocket which react can't track. In re-renders, the value stored in reference variable will not be lost or reset. It's similar to useState but there is a key difference.&lt;/p&gt;

&lt;h3&gt;
  
  
  Difference btw useRef and useState
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;If we change any state variable, the whole component re-renders, but if we update any reference variable, there is no re-render.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;useRef is used rarely where the data is not needed for rendering. (For e.g- our IntervalID which is a timeout function). Use useState when you want to display that data in component and update it. (For e.g- counter button)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To know more in-depth use cases for useRef, checkout &lt;a href="https://react.dev/learn/referencing-values-with-refs" rel="noopener noreferrer"&gt;Link&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing useRef in our Stopwatch
&lt;/h2&gt;

&lt;p&gt;Let's focus back on our Stopwatch, we just have to store the IntervalID in reference variable with the help of useRef Hook.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Import the useRef Hook&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpbejy6i3zrjxhmasenqm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpbejy6i3zrjxhmasenqm.png" alt="importing useRef hook" width="582" height="40"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Initialize the variable&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;const intervalID = useRef(null);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Initially, we are giving it a null (empty) value instead of 0.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;.current Property&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, this IntervalID is an object which only has one property - .current&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
        current: value //null in our case
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To update or change the value, we have to use .current property.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Updating the Start Function
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const start = () =&amp;gt; {

        if (!isRunning) {
            intervalID.current = setInterval(() =&amp;gt; {
                setCurrentTime((prevTime) =&amp;gt; {
                    return prevTime + 10;
                })
            }, 10)
        }

        setIsRunning(true);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Updating the Stop Function
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const stop = () =&amp;gt; {
        if (isRunning) {
            clearInterval(intervalID.current);
            setIsRunning(false);
        }

    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Updating the Reset Function
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const reset = () =&amp;gt; {
        clearInterval(intervalID.current);
        setCurrentTime(0);
        setIsRunning(false);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And its done! Our Simple Stopwatch is built! Give a self-pat on your back and let's do the final touches.&lt;/p&gt;

&lt;h2&gt;
  
  
  useEffect to clean up any remaining IntervalID
&lt;/h2&gt;

&lt;p&gt;We don't want that if we start our program there is some residual leftover IntervalID, so we can use a useEffect Hook that will only take effect on mounting the component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useEffect(() =&amp;gt; {
        return () =&amp;gt; clearInterval(intervalID.current);
    }, []);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Source Code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useRef, useEffect } from "react"

export default function Stopwatch() {

    const [currentTime, setCurrentTime] = useState(0);
    const [isRunning, setIsRunning] = useState(false);

    const intervalID = useRef(null);



    const start = () =&amp;gt; {

        if (!isRunning) {
            intervalID.current = setInterval(() =&amp;gt; {
                setCurrentTime((prevTime) =&amp;gt; {
                    return prevTime + 10;
                })
            }, 10)
        }

        setIsRunning(true);
    }




    const stop = () =&amp;gt; {
        if (isRunning) {
            clearInterval(intervalID.current);
            setIsRunning(false);
        }

    }

    const reset = () =&amp;gt; {
        clearInterval(intervalID.current);
        setCurrentTime(0);
        setIsRunning(false);
    }

    useEffect(() =&amp;gt; {
        return () =&amp;gt; clearInterval(intervalID.current);
    }, []);


    return (
        &amp;lt;&amp;gt;
            &amp;lt;h2&amp;gt;{(currentTime / 1000).toFixed(2)}&amp;lt;/h2&amp;gt;
            &amp;lt;button onClick={start}&amp;gt;Start&amp;lt;/button&amp;gt;
            &amp;lt;button onClick={stop}&amp;gt;Stop&amp;lt;/button&amp;gt;
            &amp;lt;button onClick={reset}&amp;gt;Reset&amp;lt;/button&amp;gt;
        &amp;lt;/&amp;gt;
    )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks for reading till here, we can improve this stopwatch to make it more fancy but we are not gonna cover that in this blog. This is a beginner guide to understand the internal working.&lt;/p&gt;

&lt;p&gt;All the best on your Coding Journey!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
