1.需求及分析
最近,接到一个接收手机验证码的功能,大体就是设置一个定时器,在每次执行的时候将秒数,逐个减去1,小于0的时候,清除定时器,然后完善一下功能,例如,加上一下状态的变化,总结下整体逻辑为:
开始进入,文字显示:获取验证码,点击后,开始倒计时显示,重新获取+秒数状态置为灰色,倒计时结束,只改变状态并重置秒数。
2.代码实现
// 时间的颜色状态
const [time_disbaled, set_time_disbaled]: [boolean, React.Dispatch<React.SetStateAction<boolean>>] = useState<boolean>(false);
// 是否是第一次进入页面(为了判断文字的显示)
const [init_status, set_init_status]: [boolean, React.Dispatch<React.SetStateAction<boolean>>] = useState<boolean>(true);
// 秒数
const [seconds, set_seconds]: [any, React.Dispatch<React.SetStateAction<any>>] = useState<any>(null);// 秒数不存在的时候,颜色需要立即置为可点击状态useEffect(() => {if (!seconds) {set_time_disbaled(false);}}, [seconds, set_time_disbaled])// 倒计时const countDown = useCallback(() => {let s = seconds || 5;// 这里为了第一时间把倒计时的值显示出来s && set_seconds(s);let siv = setInterval(() => {s -= 1;if (s < 0) {clearInterval(siv);} else {set_seconds(s);}}, 1000);}, [seconds, set_seconds])// 获取验证码const getVerifyCode = useCallback(() => {set_time_disbaled(true);countDown();init_status && set_init_status(false);}, [set_time_disbaled, set_init_status, init_status])// html
<Form.Item name='verifyCode'><Row align="middle" className="verifyCode"><Col sm={15}><Input size='large' placeholder={formatMessage({id: 'p_i_verify'})} /></Col><Col className={`time ${time_disbaled ? 'diabledStyle': ''}`}><Button disabled={time_disbaled} onClick={getVerifyCode}>{init_status ? <span>获取验证码</span>: <span>重新发送{seconds > 0 && `${seconds}s`}</span>}</Button></Col></Row></Form.Item>
下面这句代码很重要,如果不写的话,第一时间赋的值,不会显示,会直接进行减一的操作。
3.小结
写倒计时记住:
1)使用定时器,每秒减1,获取变量;
2)秒数需要写到小于0时停止,因为我们需要记录一下数据,如果1是最后一个,减1之后会执行定时器,则0秒不会记录在state数据中心,导致页面的问题;