在做一个声音播放的前端页面,接入了讯飞的文字生成语音接口,需要在组件内部判断声音是否播放完毕。组件内似乎无法直接获取class内部状态,于是用了计时器轮询的方法,在点击播放声音后开启定时器,监测到声音播放完成后关闭计时器。 本以为写两行setInterval/clearInterval就完事儿了,没想到被卡bug卡了一下午,百思不得其解,翻了很多帖子,最终发现原来要把定时器写在组件外面;不然的话,组件内的依赖项变化时会重开计时器。 示例代码如下:
var interval, intervalList = []
const Template = () => {
const [isTick, setIsTick] = useState(0)
const [status, setStatus] = useState('')
//开启定时器
useEffect(() => {
interval = setInterval(() => {
console.log("jishi");
}, 2000)
intervalList.push(interval)
}, [isTick])
//关闭定时器
useEffect(()=>{
clearInterval(interval)
interval = 0
intervalList.forEach((item, index) => { clearInterval(item) })
intervalList = []
}
}, [status])
return (
<div>
<div onClick={()=>{setIsTick(1)}}>开始计时</div>
<div onClick={()=>{setStatus('1')}}>停止计时</div>
</div>
)
}
export default Template
总之有两点: 1.维护一个intervalList,清空定时器要同时清空该list; 2.定时器定义在组件外部(用useRef好像也可以,懒得试了)