点击就产生60秒倒计时的按钮->点击后就会执行某操作,立刻开启倒计时x秒,倒计时结束才能再次能够点击。

点击就产生60秒倒计时的按钮

点击后就会执行某操作,立刻开启倒计时x秒,倒计时结束才能再次能够点击。

export function subscribeInterval(ms, task) {
    const handle = setInterval(task, ms);
    return () => clearInterval(handle);
}

export const useInterval = (ms, task) => useEffect(() => subscribeInterval(ms, task), []);


export function CountDownButton({countDown, normalText, waitText, task, ...props}) {
    const [count, setCount] = useState(0);
    const [isWait, setIsWait] = useState(false);
    const timer = useRef(-1);
    // const wait = ()=>{
    //     clearInterval(timer.current);
    //     timer.current = setInterval(()=>{
    //         setCount(count => count -1);
    //         if(count <= 0){
    //             setIsWait(false);
    //             clearInterval(timer.current);
    //             setCount(countDown);
    //             console.log(count);
    //             console.log("??");
    //         }
    //     }, 1000);
    // };
    useEffect(()=>{
        clearInterval(timer.current);
        timer.current = setInterval(()=>{
            setCount(count => count -1);
            console.log(count)
            if(count == 0){
                setIsWait(false);
                clearInterval(timer.current);
                console.log(count);
                console.log("??");
            }

        }, 1000);
    }, [count]);
    // useEffect(()=>{
    //     console.log("111");
    //     setCount(countDown);
    // },[countDown])
    return <>
        <Button type="primary" disabled={isWait} onClick={() => {
            task();
            setIsWait(true);
            setCount(countDown);
        }} {...props}>{isWait ?count + "秒后" + waitText : normalText}</Button>
    </>
}

第二天想起来,这段代码显然是有问题的,虽然它的效果看着挺正常的……它现在的效果是:count改变->useEffect内部执行清除定时器,然后又创建定时器,然后对count进行-1操作->useEffect执行,清除刚刚的定时器,又创建新的定时器……

所有它其实一直是创建定时器,-1,清除刚刚的定时器,创建新的定时器,-1,清除,创建……这样虽然基本上是1秒减1,但是其实完全不是我想要的效果。

后来想了一下,应该是开始等待isWait为true时,启动计时器,在计时器进行了countDown次操作后,清除计时器。同时在useEffect执行的那一刻,就形成了一个闭包,此时在计时器里面的count都是形成闭包时的数据,也就是计时器每次运行时,count还是一开始的count(但是因为是setCount(count => count-1)这样写的,外部的count是正常地进行着1秒减1的操作的。所以我加了一个局部变量,-1操作的次数都用它来记录,当达到倒计时要求的次数时,就可以终止倒计时了。可能有点冗余,但是应该是对的哈哈:

useEffect(()=>{
            if(isWait === true){
                clearInterval(timer.current);
                let countTime = 0;
                timer.current = setInterval(()=>{
                    setCount(count => count -1);
                    countTime ++;
                    if(countTime === countDown){
                        setIsWait(false);
                        clearInterval(timer.current);
                    }
                }, 1000);
            }
        }, [isWait]);
posted @ 2021-01-07 18:55  团叽  阅读(393)  评论(0编辑  收藏  举报