React Hooks与setInterval相撞时

54 阅读1分钟

在做一个声音播放的前端页面,接入了讯飞的文字生成语音接口,需要在组件内部判断声音是否播放完毕。组件内似乎无法直接获取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好像也可以,懒得试了)