在倒数计时器中动态更新道具时遇到问题 - 使用反应钩子创建
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 组件的 componentDidMount
、componentDidUpdate
和 componentWillUnmount
生命周期函数的功能组件。我们对“更新”生命周期感兴趣。
useEffect(() => {
setTimer((timer) => ({
...timer, // copy existing state
timeRemaining: props.cycleTimeSelected // update property
}));
}, [props.cycleTimeSelected]);
我是 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 组件的 componentDidMount
、componentDidUpdate
和 componentWillUnmount
生命周期函数的功能组件。我们对“更新”生命周期感兴趣。
useEffect(() => {
setTimer((timer) => ({
...timer, // copy existing state
timeRemaining: props.cycleTimeSelected // update property
}));
}, [props.cycleTimeSelected]);