【问题标题】:React countdown timer反应倒计时
【发布时间】:2021-07-19 07:41:35
【问题描述】:

我有一个倒数计时器 sn-p 反应如下:

const [remainingTime, setRemainingTime]: [number, Dispatch<SetStateAction<number>>] = useState<number>(0);
const [updatedTime, setUpdatedTime]: [number, Dispatch<SetStateAction<number>>] = useState<number>(0);
const referenceTime = useRef<number>(0); // new Date().getTime()
const intervalRef = useRef<number>(updatedTime);

const decreaseTime = () =>
        setUpdatedTime((prevState) => {
            if (prevState > 1) {
                    return parseFloat(((updatedTime * 1000 + referenceTime.current - Date.now()) / 1000).toFixed(0));
            } else {
                setRemainingTime(0);
                return 0;
            }
        });
    
    useEffect(() => {
        if (remainingTime > 0) {
            intervalRef.current = setInterval(decreaseTime, 1000) as unknown as number;
        }

        return () => clearInterval(intervalRef.current);
}, [remainingTime]);

在我想为其添加增量和减量选项之前,一切正常。有必要使用 Date.now() 和 referenceTime 因为这个模块用于 react-native 并且它必须在后台模式下工作,所以我应该在哪里改变一些东西来正确升级状态。我尝试了以下解决方案:

setUpdatedTime((prevState) => prevState + 10)

setUpdatedTime((prevState) => updatedTime + 10)

更新: https://codesandbox.io/s/react-countdown-timer-lr9sb

感谢您的帮助。 :)

【问题讨论】:

  • 如何使用 moment.js - momentjs.com/docs/#/manipulating/add 更好地处理日期和时间。
  • 其实我不用修改Date对象,我的问题是updatedTime没有正确更新。
  • 您能澄清一下问题所在吗?
  • @DrewReese 如果我尝试增加或减少几秒,倒计时计时器变得疯狂,因为 prevState 和 updatedTime 没有同时改变,所以我为 updatedTime 设置了一个新值更改渲染周期,但在 nextState 中跳回 prevState。例如,我的计时器状态是 45,我添加 +10 秒,然后它将是 55/54 秒,然后跳回到 44。
  • @DrewReese 我附上了一个代码框,它可能有助于了解实际情况。

标签: javascript reactjs typescript react-native


【解决方案1】:

如果有人处于相同情况的解决方案: https://codesandbox.io/s/react-countdown-timer-lr9sb?file=/src/App.tsx

const [remainingTime, setRemainingTime]: [number, Dispatch<SetStateAction<number>>] = useState<number>(0);
const [updatedTime, setUpdatedTime]: [number, Dispatch<SetStateAction<number>>] = useState<number>(0);
const referenceTime = useRef<number>(0); // new Date().getTime()
const intervalRef = useRef<number>(updatedTime);

const decreaseTime = () =>
        setUpdatedTime((prevState) => {
            const difference = parseFloat((Date.now() - referenceTime.current - 1000).toFixed(0))
            if (prevState > 1) {
                    return parseFloat(((prevState * 1000 + referenceTime.current - Date.now() + (difference)) / 1000).toFixed(0));
            } else {
                setRemainingTime(0);
                return 0;
            }
        });
    
    useEffect(() => {
        if (remainingTime > 0) {
            intervalRef.current = setInterval(decreaseTime, 1000) as unknown as number;
        }

        return () => clearInterval(intervalRef.current);
}, [remainingTime]);

【讨论】:

  • 只是粗略的一瞥,但我认为你基本上是(prevState * 1000 + ref.current - now + (now - ref.current - 1000)) / 1000,它简化为(prevState * 1000 - 1000) / 1000 => (1000 / 1000) * (prevState * 1 - 1) / 1,或prevState - 1。如果此解决方案对您有用,现在似乎无关紧要。因此,即使在后台运行一段时间(30 多秒)后,这也能正确计算下一个状态?
  • 这是一个很好的问题,我没想过我会测试它。 :D
猜你喜欢
  • 2020-10-23
  • 2020-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-18
  • 2021-02-01
  • 2019-08-12
  • 1970-01-01
相关资源
最近更新 更多