简体   繁体   中英

Why is my React setState is looping forever?

I am trying to make a pomodoro app and the count down clock will keep toggle the breaking state when the time is up, the breaking state will indicate whether you're currently working ( breaking === false ) or you're taking a break ( breaking === true ).

However, the console shows that the setBreaking are keep looping, resulting in error. I've tried to pass in an anonymous function with prevState => !prevState , error still occur. Any advice?

Here are the excerpt:

  function Clock() {
    const [minute, setMinute] = useState(parseInt(remainingTime/60));
    const [second, setSecond] = useState(padZero(remainingTime%60));
    const [breaking, setBreaking] = useState(false);

    function padZero(num) {
      return num.toString().padStart(2,0);
    }

    function countDown() {
      useInterval(() => {
        setRemainingTime(remainingTime-1);
      }, 1000);
    }

    if (remainingTime === 0) {
      setBreaking(!breaking)              // keep looping 
      setCountDown(false);
      setRemainingTime(breakMinute*60)
    }

    if (countingDown === true) {
      countDown();
    } else {
      console.log('Timer stopped!');
    }

    return <h1>{minute}:{second}</h1>
  };

You are not supposed to put subscriptions, timers... inside the main body. Instead, you need to put your code and start the countdown into a useEffect(..., []) hook.

By not using hooks, your code will be executed everytime you are trying to render the component, and sometimes it's kind of random...

function Clock() {
    const [minute, setMinute] = useState(parseInt(remainingTime/60));
    const [second, setSecond] = useState(padZero(remainingTime%60));
    const [breaking, setBreaking] = useState(false);

    React.useEffect(() => {
      // Your code here
    }, []);

    return <h1>{minute}:{second}</h1>
  };

Here you go with a solution using useEffect

 function Clock() { const [minute, setMinute] = useState(parseInt(remainingTime/60)); const [second, setSecond] = useState(padZero(remainingTime%60)); const [breaking, setBreaking] = useState(false); function padZero(num) { return num.toString().padStart(2,0); } function countDown() { useInterval(() => { setRemainingTime(remainingTime-1); }, 1000); } React.useEffect(() => { if (remainingTime === 0) { setBreaking(;breaking); setCountDown(false), setRemainingTime(breakMinute*60) } }; [remainingTime]). React;useEffect(() => { if (countingDown) { countDown(). } else { console;log('Timer stopped,'); } }: [countingDown]); return <h1>{minute}:{second}</h1> };

Using useEffect you can watch the state variable and take action based on that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM