Having trouble making a prop update dynamically in countdown timer - create with a react hook

367 views Asked by At

I'm new to React and building a project that requires dynamically setting a countdown timer from a parent component. I found a react countdown timer online that uses a hook, but I'm not too familiar hooks yet.

Toward the bottom of my code, you can see a parent class where I'm passing 'cycleTimeSelected' to the Countdown component/hook. It works correctly up to that point.

But I'm not having success getting it to update the timer correctly and dynamically. timeRemaining in React.useState() is the variable I need to update. It doesn't work if I use props.cycleTimeSelected directly. I think I understand why that is, so I tried to use componentWillRecieveProps to set the state, but that's not working.

I'm think I'm confused about React.useState and how that relates to setState for one thing. Can anyone spot my problem here?

import React, { Component } from 'react'
import { PausePresentation, SkipNext, Stop, PlayCircleOutline} from '@material-ui/icons';

import './Timer.css'



function Countdown(props) {

    const [timer, setTimer] = React.useState({
      name: 'timer',
      isPaused: true,
      time: 100,
      timeRemaining: props.cycleTimeSelected,
      timerHandler: null
    })

    //const componentWillReceiveProps = nextProps => {
      //this.setState({ timeRemaining: nextProps.cycleTimeSelected });  
    //}



    const handleTimeChange = e => {
    
      setTimer({
        ...timer,
        time: props.cycleTimeSelected,
        timeRemaining: Number(e.target.value),
      })
    }

    React.useEffect(() => {
      if (timer.timeRemaining === 0) {
        clearInterval(timer.timerHandler)
      }
    }, [timer.timeRemaining, timer.timerHandler])
   
    const updateTimeRemaining = e => {
      setTimer(prev => {
        return { ...prev, timeRemaining: prev.timeRemaining - 1 }
      })
    }
    const handleStart = e => {
      const handle = setInterval(updateTimeRemaining, 1000);
      setTimer({ ...timer, isPaused: false, timerHandler: handle })
    }
    const handlePause = e => {
      clearInterval(timer.timerHandler)
      setTimer({ ...timer, isPaused: true })
    }
    return <React.Fragment>
      {/* { <input value={props.cycleTimeSelected} type="" onChange={handleTimeChange} /> } */}
        {timer.name && timer.time && <div className={timer.timeRemaining === 0 ? 'time-out':''}>
        {timer.isPaused &&  <div className="floatLeft"><i className="material-icons pause"><PlayCircleOutline onClick={handleStart}></PlayCircleOutline></i></div>}
        {!timer.isPaused &&  <div className="floatLeft"><i className="material-icons pause"><PausePresentation onClick={handlePause}></PausePresentation></i></div>}
     
        {`Remaining: ${timer.timeRemaining}`}
      </div>}
    </React.Fragment>
  }




class Timer extends React.Component {

render(){

        return(
            <>
                <div className="floatLeft"><i className="material-icons bottom-toolbar stop"><Stop onClick={this.clickStop}></Stop></i></div>
                <div className="floatLeft"><i className="material-icons bottom-toolbar skip_next"><SkipNext onClick={this.clickSkip}></SkipNext></i></div>
                <div className="floatLeft"><div id="timer"><Countdown cycleTimeSelected={this.props.cycleTimeSelected}></Countdown></div></div>
            </>
        );
    }

}
1

There are 1 answers

0
Drew Reese On BEST ANSWER

If you want timer.timeRemaining in Countdown to update via props then you should implement an effect with a dependency on props.cycleTimeSelected. useEffect is nearly the functional component equivalent to a class-based component's componentDidMount, componentDidUpdate, and componentWillUnmount lifecycle functions. We're interested in the "update" lifecycle.

useEffect(() => {
  setTimer((timer) => ({
    ...timer, // copy existing state
    timeRemaining: props.cycleTimeSelected // update property
  }));
}, [props.cycleTimeSelected]);

Edit having-trouble-making-a-prop-update-dynamically-in-countdown-timer-create-with