skip to Main Content

I am making a countdown app using React JS and Tailwind CSS and currently the countdown is running on manual input from the useState hook but I want to take the input from the user and when the user clicks the submit button then I want to start the countdown.
Please could someone help me – I have been stuck on this for the last 2 hours! Thanks!

Here is the code:

App.js –

import React from 'react'
import CountDown from './components/CountDown'

const App = () => {
  return (
    <div>
      <CountDown/>
    </div>
  )
}

export default App

CountDown.js-

import React, { useState, useEffect, useRef } from 'react'

const CountDown = () => {
  const [count, setCount] = useState(10);
  let cntVal = useRef();

  const handleChange = e =>{
    setCount(e.target.value)
  }

  const handleSubmit = () =>{
    if(count < 0){
      alert("Count cannot be negative!");
      return;
    }
  }

  useEffect(() => {
    cntVal.current = setInterval(() => {
      setCount(prev => prev - 1)
    }, 1000)
    return () => clearInterval(cntVal.current)
  },[]);

  useEffect(() => {
    if(count === 0){
      clearInterval(cntVal.current);
      alert("END!")
    }
  })
  
  return (
    <div className='h-[100vh] w-full flex flex-col items-center justify-center'>
      <div className="border border-black p-12 items-center justify-center">
        <div className="flex justify-center">
          <p className='text-3xl font-bold'>Countdown App</p>
        </div>
        <div className="flex justify-center mt-10">
          <p className='font-semiboldld text-2xl'>{count}</p>
        </div>
        <div className="flex mt-10 mb-4 items-center justify-center">
          <label htmlFor="name" className='text-xl'>Enter a Number: </label>
          <input className='border border-black ml-2 p-2 rounded-lg text-xl' type="text" name="cntDown" ref={cntVal} id="cntDown" onChange={handleChange} />
        </div>
        <div className="flex justify-center">
          <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" onClick={handleSubmit}>
            Submit
          </button>
        </div>
      </div>
    </div>
  )
}

export default CountDown

2

Answers


  1. You can start the countdown from the handleSubmit function:

    const handleSubmit = () =>{
        if(count < 0){
          alert("Count cannot be negative!");
          return;
        }
        cntVal.current = setInterval(() => {
          setCount(prev => prev - 1)
        }, 1000)
      }
    

    The only other change is in your ‘unmount’ logic, check if (cntVal.current) is set before calling clearInterval(cntVal.current);

    const {  useState, useEffect, useRef } = React;
    
    const CountDown = () => {
      const [count, setCount] = useState(10);
      let cntVal = useRef();
    
      const handleChange = e =>{
        setCount(e.target.value)
      }
    
      const handleSubmit = () =>{
        if(count < 0){
          alert("Count cannot be negative!");
          return;
        }
        cntVal.current = setInterval(() => {
          setCount(prev => prev - 1)
        }, 1000)
      }
    
      useEffect(() => {
        return () => {
            if (cntVal.current) {
                clearInterval(cntVal.current);
            }
    
        }
      },[]);
    
      useEffect(() => {
        if(count === 0){
          clearInterval(cntVal.current);
          alert("END!")
        }
      })
      
      return (
        <div className='h-[100vh] w-full flex flex-col items-center justify-center'>
          <div className="border border-black p-12 items-center justify-center">
            <div className="flex justify-center">
              <p className='text-3xl font-bold'>Countdown App</p>
            </div>
            <div className="flex justify-center mt-10">
              <p className='font-semiboldld text-2xl'>{count}</p>
            </div>
            <div className="flex mt-10 mb-4 items-center justify-center">
              <label htmlFor="name" className='text-xl'>Enter a Number: </label>
              <input className='border border-black ml-2 p-2 rounded-lg text-xl' type="text" name="cntDown" ref={cntVal} id="cntDown" onChange={handleChange} />
            </div>
            <div className="flex justify-center">
              <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" onClick={handleSubmit}>
                Submit
              </button>
            </div>
          </div>
        </div>
      )
    }
    
    ReactDOM.render(<CountDown />, document.getElementById("react"));
    
    ReactDOM.render(<CountDown />, document.getElementById("react"));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
    <div id="react"></div>
    Login or Signup to reply.
  2. look here

    import React, { useState, useEffect, useRef } from 'react'
    
     const CountDown = () => {
     const [count, setCount] = useState(10);
     const [userCount, setUserCount]= useState(0);
     let cntVal = useRef();
    
     const handleChange = e =>{
     setUserCount(e.target.value);
     }
    
     const handleSubmit = () =>{
       if(userCount < 0){
        alert("Count cannot be negative!");
        return;
      }
       setCount(userCount);
      }
    
     useEffect(() => {
      cntVal.current = setInterval(() => {
        setCount(prev => prev - 1)
       }, 1000)
      return () => clearInterval(cntVal.current)
      },[]);
    
     useEffect(() => {
      if(count === 0){
          clearInterval(cntVal.current);
         alert("END!")
        }
       })
    
      return (
    <div className='h-[100vh] w-full flex flex-col items-center justify-center'>
      <div className="border border-black p-12 items-center justify-center">
        <div className="flex justify-center">
          <p className='text-3xl font-bold'>Countdown App</p>
        </div>
        <div className="flex justify-center mt-10">
          <p className='font-semiboldld text-2xl'>{count}</p>
        </div>
        <div className="flex mt-10 mb-4 items-center justify-center">
          <label htmlFor="name" className='text-xl'>Enter a Number: </label>
          <input className='border border-black ml-2 p-2 rounded-lg text-xl' type="text" name="cntDown" ref={cntVal} id="cntDown" onChange={handleChange} />
        </div>
        <div className="flex justify-center">
          <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" onClick={handleSubmit}>
            Submit
          </button>
        </div>
      </div>
    </div>
         })
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search