【问题标题】:React Timer using functional Hooks | Timer is not stopping使用功能性 Hooks 的 React Timer |计时器没有停止
【发布时间】:2021-07-23 17:19:43
【问题描述】:

我想使用钩子 useStateuseEffects 创建一个 60 秒的反应时间,这就是我正在做的事情

import '../assets/css/timer.css'
import { useState, useEffect } from 'react'

const Timer = () =>{

    const [ time, setTime ] = useState(0);

    useEffect(()=>{
        if(time!==60){
            setInterval(()=>{
                    setTime(prevTime => prevTime+1) ;
            }, 1000);
        }
        
    
    }, [])


    return(
        <>

            <div className="circular">
                <div className="inner"></div>
                <div className="outer"></div>
                <div className="numb">
                    {time}  // Place where i am displaying time
                </div>
                <div className="circle">
                    <div className="dot">
                    <span></span>
                    </div>
                    <div className="bar left">
                    <div className="progress"></div>
                    </div>
                    <div className="bar right">
                    <div className="progress"></div>
                    </div>
                </div>
            </div>
        </>
    )
}

export default Timer

定时器没有停止。它会永远持续下去。这个我也试过了

    useEffect(()=>{

        setInterval(()=>{
            if(time!==60)
                setTime(prevTime => prevTime+1) ;
        }, 1000);
    
    }, [])

请大家解释一下哪里出了问题。

【问题讨论】:

  • 你的依赖数组是空的,所以效果只运行一次 - 而time 显然不是 60。您需要将time 添加到依赖数组中,并在效果内返回一个清理函数(否则您将逐渐添加越来越多的间隔,因此时间似乎会不断“加速”)

标签: javascript reactjs react-hooks


【解决方案1】:

useEffect(..., []) 只会运行一次,所以其中的time 永远不会更新。所以你需要检查setTime函数内部的prevTime,如果它不是60则只增加。如果它,你应该清除间隔,然后你应该清除间隔useEffect 的清理:

useEffect(()=>{
    const i = setInterval(() => {
        setTime(prevTime => {
            if (prevTime !== 60) return prevTime+1;
            clearInterval(i);
            return prevTime;
        });
    }, 1000);
    return () => clearInterval(i);
}, [])

【讨论】:

    【解决方案2】:

    您的第一次尝试已经接近成功,但存在一些问题。

    主要问题是您传递了一个空的依赖数组,这意味着它只会在第一次渲染时运行,而不会在后续渲染时更新。其次,您没有提供退货或“清理”,这意味着间隔永远不会被清除。

      useEffect(() => {
        if (time < 60) {
          const timer = setInterval(() => {
            setTime(prevTime => prevTime + 1);
          }, 1000);
    
          return () => clearInterval(timer);
        }
      }, [time])
    

    在这里,我们在依赖数组中传递 time 并有条件地设置间隔,如果 time 小于您的结束时间,在您的情况下为 60,但我将其缩短为 5,以便您可以看到它停止。我们还传递了一个return 回调,它将在每个渲染周期结束时清除间隔。

    使用此设置,每次 setInterval 更新 time 状态时,useEffect 将在上一次渲染结束时清除间隔,然后在当前渲染中重新运行,如果时间小于限制。

    以这种方式使用 React 渲染周期而不是清除间隔回调中的间隔的优势在于,它可以让您精细控制超时 - 允许您轻松添加进一步检查或根据其他状态值。

    const { useState, useEffect } = React;
    
    const Timer = () => {
      const [time, setTime] = useState(0);
    
      useEffect(() => {
        if (time < 5) {
          const timer = setInterval(() => {
            setTime(prevTime => prevTime + 1);
          }, 1000);
    
          return () => clearInterval(timer);
        }
      }, [time])
    
      return (
        <div className="circular">
          <div className="numb">
            {time}
          </div>
        </div>
      )
    }
    
    ReactDOM.render(
      <Timer />,
      document.getElementById("root"));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
    
    <div id="root"></div>

    【讨论】:

      【解决方案3】:

      你必须在卸载状态下清除 setTimeout

      用于功能组件

      // Funtional component
      useEffect(()=>{
        const i = setInterval(() => {
          setTime(prevTime => {
              if (prevTime !== 60) return prevTime+1;
              clearInterval(i);
              return prevTime;
          });
        }, 1000);
        return () => clearInterval(i);
      }, [])
      

      对于类组件

      // Class component
      componentWillUnmount() {
        this.clearInterval()
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-04-11
        • 1970-01-01
        • 2023-03-30
        • 1970-01-01
        • 2022-06-15
        • 2020-09-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多