在倒数计时器中动态更新道具时遇到问题 - 使用反应钩子创建

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

我是 React 的新手,正在构建一个需要从父组件动态设置倒数计时器的项目。我在网上找到了一个使用hook的react倒数计时器,但是我对hook还不是很熟悉

在我的代码底部,您可以看到我将 'cycleTimeSelected' 传递给倒计时 component/hook 的父项 class。到那时它都可以正常工作。

但是我没有成功地让它正确动态地更新计时器。 React.useState() 中的 timeRemaining 是我需要更新的变量。直接用props.cycleTimeSelected不行。我想我明白为什么会这样,所以我尝试使用 componentWillRecieveProps 来设置状态,但这不起作用。

我想我对 React.useState 感到困惑,一方面是它与 setState 的关系。谁能在这里发现我的问题?

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>
            </>
        );
    }

}

如果您希望 Countdown 中的 timer.timeRemaining 通过 props 更新,那么您应该实现一个依赖于 props.cycleTimeSelected 的效果。 useEffect 几乎是相当于 class-based 组件的 componentDidMountcomponentDidUpdatecomponentWillUnmount 生命周期函数的功能组件。我们对“更新”生命周期感兴趣。

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