,

React验证码倒计时问题

直接在定时器里 –leftTime 原地修改 state 变量,state 是 const 也不能直接改,而…

let [leftTime, setLeftTime] = useState(60);
    const [codeStatus, setCodeStatus] = useState(true);
    
    const runTime = () => { 
        const timer = setInterval(()=>{
            setLeftTime(--leftTime);
            if(leftTime <= 0){
                clearInterval(timer);
                setCodeStatus(true);
                setDisabled(false);
            }
        },1000)
}

直接在定时器里 --leftTime 原地修改 state 变量,state 是 const 也不能直接改,而且闭包捕获了初始值,倒计时会错乱;同时用 let 只是表象,根本错误是同步修改 state 值、闭包陷阱。

优化后

import React from 'react';
import IconMap from 'components/IconMap.jsx';
import { LoginRule } from 'utils/rules';
import { Space } from 'antd';
const { Compact } = Space;
import { useState } from 'react';
const SmCodeLogin = ({form, FormItem, Input, Button}) => {
    const handleSendCode = () => {
        console.log('发送验证码');
        setCodeStatus(false);
        setLeftTime(60);
        setDisabled(true);
        runTime();
    }
    const [disabled, setDisabled] = useState(true);
    const [leftTime, setLeftTime] = useState(60);
    const [codeStatus, setCodeStatus] = useState(true);
    
    const runTime = () => { 
        const timer = setInterval(()=>{
            setLeftTime(prev=>{
                if(prev <= 1){
                    clearInterval(timer);
                    setCodeStatus(true);
                    setDisabled(false);
                    return 0;
                }   
                return prev-1;
            });
            
        },1000)
    }

    const checkMobile = async (e) => {
        console.log(e.target.value,'e.target.value');
        //const status = await form.validateFields(['mobile']);
        //因为返回的promise2种状态采用trycatch处理
        try{
            const data = await form.validateFields(['mobile']);
            console.log(data,'data');
            setDisabled(false);
        }catch(error){
            console.log(error,'error');
            setDisabled(true);
        }
    }
    return (
        <>
            <FormItem
                name="mobile"
                rules={LoginRule.mobileRule}
                hasFeedback={true}
            >
                <Input  onChange={checkMobile} prefix={IconMap.mobile} placeholder="请输入手机号" />
            </FormItem>
            <FormItem
                name="code"
                rules={LoginRule.codeRule}
                hasFeedback={true}
            >
                <Compact>
                    <Input   
                    prefix={IconMap.code} 
                    placeholder="请输入验证码"
                    // addonAfter={<Button onClick={handleSendCode}>发送验证码</Button>} 
                    />
                    <Button 
                        disabled={disabled} 
                        onClick={handleSendCode}
                    >
                        {codeStatus ? '发送验证码' : `${leftTime}秒后重新发送`}
                        
                    </Button>
                </Compact>
            </FormItem>
        </>
    );
}

export default SmCodeLogin;

再次优化,解决定时器未销毁问题

import { useState, useRef, useEffect } from 'react';
const SmCodeLogin = ({form, FormItem, Input, Button}) => {
    const handleSendCode = () => {
        console.log('发送验证码');
        setCodeStatus(false);
        setLeftTime(60);
        setDisabled(true);
        runTime();
    }
    const [disabled, setDisabled] = useState(true);
    const [leftTime, setLeftTime] = useState(60);
    const [codeStatus, setCodeStatus] = useState(true);
      const timerRef = useRef(null);
    const runTime = () => { 
        // 防止重复点击多次开启定时器
        if (timerRef.current) return;
        setCodeStatus(false);
        timerRef.current = setInterval(()=>{
            setLeftTime(prev=>{
                if(prev <= 1){
                    clearInterval(timerRef.current);
                    timerRef.current = null;
                    setCodeStatus(true);
                    setDisabled(false);
                    return 60;
                }   
                return prev-1;
            });
        },1000)
    }

    // 组件卸载强制清定时器
    useEffect(() => {
        return () => {
            if (timerRef.current) clearInterval(timerRef.current);
        };
    }, []);

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

About the Author

每个人都有自己得时区,在自己得时区里,一切都是准时的。

BlockSpare — News, Magazine and Blog Addons for (Gutenberg) Block Editor