一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情。 在react中封装倒计时Hooks我相信大家都做过,在React+TypeScript封装自定义倒计时Hook时,遇到了一个不小坑,写这篇帖子记录下来
直接上代码分析
import { useRef, useState, useEffect } from 'react'
export default function useCountDown (initCount = 10, callback = () => {}) {
const [count, setCount] = useState(initCount) //定义倒计时数
const timer = useRef({ id: 0 }) //首先我们需要通过useRef来记录下定时器的ID
const [isEdit, setIsEdit] = useState(true) //定义状态
const start = () => {
if (!isEdit) return //开关思想,也叫节流阀,设置默认值为true,点击开启定时器时先判断状态是否为true,不为true直接return
setIsEdit(false) //进来之后把状态改成false,这是在点击就不能再触发定时器
setCount(initCount) //将调用者传过来的数赋值给倒计时数
timer.current.id = window.setInterval(() => {
setCount((count) => count - 1)
}, 1000)
}
useEffect(() => { useEffect数组里写count,只要count值发生变化就会触发useEffect
if (count === 0) { //等于零时说明倒计时走完,把状态改成true,这时候就可以在次开启新一轮倒计时
setIsEdit(true)
clearInterval(timer.current.id) //倒计时结束要清除定时器ID
callback()
}
}, [count])
useEffect(() => {
// useEffect在第一个参数里返回一个函数的话,return的函数会在组件销毁时调用
return () => {
clearInterval(timer.current.id)
}
}, []) //useEffect第二个参数是个空数组,这个useEffect只在dom渲染完毕后走一次
return { count, start, isEdit }//倒计时数、开启函数、状态
}
这段代码其实没有什么难度,主要是有一个大坑要注意!
timer.current.id = window.setInterval(() => {
setCount((count) => count - 1)
}, 1000)
}
注意这里一定要用window调用setInterval,setInterval既可以在node中使用,也可以浏览器中使用,默认是在node里运行的类型。我们这里需要通过useRef获取定时器的ID,如果这里不用window调用,setInterval默认node的类型,我们查看签名就可以得知,node的类型不是我们需要的,而且会一直报错,所以必须要用window调用!
然后在相关的组件中,直接导入函数,使用我们导return出的逻辑就行
{isEdit ? '发送验证码' : `${count}秒后获取`}