由于某种原因,我的计时器在修改输入字段后没有更新它的内部计时器状态。这是我的页面和状态的初始状态。
这是我将输入从 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, isRunning, start, stop, }
}
我的完整代码库在这里,以防有人感兴趣:https://github.com/kamilski81/bdt-coach
答案 0 :(得分:1)
这是您期望的事件序列:
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);
};