【问题标题】:SetInterval can't be stopped by clearInterval when using useEffect使用 useEffect 时无法通过 clearInterval 停止 SetInterval
【发布时间】:2021-12-19 14:56:57
【问题描述】:

我尝试实现一个函数,当 isPlaying 变量为真时开始倒计时,当它为假时停止,一般来说,它不起作用,它所做的只是同时启动多个间隔, 当视频停止或重新开始播放时,isPlaying 会发生变化

 let interval
    useEffect(() => {
            if (isPlaying) {
                interval = setInterval(() => {
                    setTimePassed((time) => time + 1)
                }, 1000);
            } else {
                console.log('clear interval');
                clearInterval(interval);
            }
            return () => clearInterval(interval);
        }, [isPlaying])

【问题讨论】:

  • 你不能在 React 中那样使用闭包变量。如果您想在函数组件中保持状态(例如 setInterval 句柄的值),请使用 useState
  • @JaredSmith 我认为这里不是这种情况,这里的间隔只是用来跟踪从 setInterval 返回的 id,以便可以将其传递给 clearInterval,尽管无法回答,除非OP 提供了提及 isPlaying 的代码。
  • @CodeManiac 为什么闭包中的变量会在多个不同的调用中持续存在? React 不保证它何时重新渲染你的 FC,clearInterval 会很乐意接受nullundefined 并且没有操作。这就是钩子的真正用途。

标签: javascript reactjs react-hooks


【解决方案1】:

您需要将间隔存储在 useRef 挂钩中,因为组件重新渲染您的间隔值设置为取消定义,因为它不保留状态

let interval = useRef();
useEffect(() => {
        if (isPlaying) {
          interval.current = setInterval(() => {
                setTimePassed((time) => time + 1)
            }, 1000);
        } else {
            console.log('clear interval');
            clearInterval(interval.current);
        }
        return () => clearInterval(interval.current);
    }, [isPlaying])

【讨论】:

    【解决方案2】:

    这对我有用,我只是将区间放在函数边界之外,并在清除区间时引用 _id。

    let interval = null
    export default function PlayerBar() {
        const [isReady, setIsReady] = useState(false)
        const [isPlaying, setIsPlaying] = useRecoilState(store.playingState)
        const [volume, setVolume] = useState(100)
        const [duration, setDuration] = useState<number>()
        const [timePassed, setTimePassed] = useState<number>(0)
        // const [intervalStatus, setIntervalStatus] = useState<any>()
        const player = useRef<any>()
        const timePassedStatus = useMemo(() => duration - timePassed, [timePassed])
        const durationStatus = useMemo(() => ('' + (duration / 60)).split('.').join(':'), [duration])
        useEffect(() => {
            if (isPlaying) {
                interval = setInterval(() => {
                    setTimePassed((time) => time + 1)
                }, 1000);
            }else if(interval){
                clearInterval(interval._id)
            }
            return () => {clearInterval(interval)};
        }, [isPlaying])
        }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-18
      • 2021-12-27
      • 2023-04-11
      • 1970-01-01
      相关资源
      最近更新 更多