如何解决为什么我的计时器钩子不更新它的内部状态?
由于某种原因,我的计时器在修改输入字段后没有更新它的内部计时器状态。这是我的页面和状态的初始状态。
这是我将输入从 10 秒修改为 8 秒后我的屏幕和状态的样子。请注意,计时器状态不会更新
function WorkoutPage(props: any) {
const DEFAULT_SECONDS_BETWEEN_REPS: number = 10
const [secondsBetweenRepsSetting,setSecondsBetweenRepsSetting] = useState(DEFAULT_SECONDS_BETWEEN_REPS)
const {secondsLeft,isRunning,start,stop} = useTimer({
duration: secondsBetweenRepsSetting,onExpire: () => sayRandomExerciseName(),onTick: () => handleTick(),})
const onTimeBetweenRepsChange = (event: any) => {
const secondsBetweenRepsSettingString = event.target.value;
const secondsBetweenRepsSettingInt = parseInt(secondsBetweenRepsSettingString)
setSecondsBetweenRepsSetting(secondsBetweenRepsSettingInt)
}
return <React.Fragment>
<input type="number" name="secondsBetweenRepsSetting" value={secondsBetweenRepsSetting} onChange={onTimeBetweenRepsChange}/>
</React.Fragment>
}
这是我的 useTimer 类:
import { useState } from 'react';
import Validate from "../utils/Validate";
import useInterval from "./useInterval";
export default function useTimer({ duration: timerDuration,onExpire,onTick}) {
const [secondsLeft,setSecondsLeft] = useState(timerDuration)
const [isRunning,setIsRunning] = useState(false)
function start() {
setIsRunning(true)
}
function stop() {
setIsRunning(false)
}
function handleExpire() {
Validate.onExpire(onExpire) && onExpire();
}
useInterval(() => {
const secondsMinusOne = secondsLeft - 1;
setSecondsLeft(secondsMinusOne)
if(secondsMinusOne <= 0) {
setSecondsLeft(timerDuration) // Reset timer automatically
handleExpire()
} else {
Validate.onTick(onTick) && onTick();
}
},isRunning ? 1000 : null)
return {secondsLeft,stop,}
}
我的完整代码库在这里,以防有人感兴趣:https://github.com/kamilski81/bdt-coach
解决方法
这是您期望的事件序列:
- 用户更改输入
- 更改处理程序触发并使用新值调用
setSecondsBetweenRepsSetting
- 组件使用
secondsBetweenRepsSetting
的新值重新渲染 -
useTimer
使用新值的duration
属性调用 -
secondsLeft
挂钩中的useTimer
状态更改为新的duration
值
为什么最后一项没有发生?因为在 useTimer
实现中,您唯一使用持续时间的地方是 secondsLeft
的初始值。使用新的持续时间值再次调用钩子不会改变 secondsLeft
状态,这是设计使然。
我的建议是将 setSecondsLeft
包含在 useTimer
挂钩的返回值中,以便您可以覆盖计时器中剩余的时间。然后,您可以直接在输入更改处理程序中使用 setSecondsLeft
:
const { secondsLeft,setSecondsLeft,isRunning,start,stop } = useTimer({
duration: secondsBetweenRepsSetting,onExpire: () => sayRandomExerciseName(),onTick: () => handleTick(),});
const onTimeBetweenRepsChange = (event: any) => {
const secondsBetweenRepsSettingString = event.target.value;
const secondsBetweenRepsSettingInt = parseInt(
secondsBetweenRepsSettingString
);
setSecondsBetweenRepsSetting(secondsBetweenRepsSettingInt);
setSecondsLeft(secondsBetweenRepsSettingInt);
};
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。