'React native infinite useEffect re-render

There's a part of chess clocks. I have a problem with endless re-renders. Idea of this part of app is pushing a one player's button leads to go opponent's time.

const App = () => {
  //initialize white
  const [whiteTime, setWhiteTime] = useState(10*60);
  const [isWhiteMove, setIsWhiteMove] = useState(false);
  
  useEffect(()=>{//make a whiteTime go countown and stop a blackTime
    if (isWhiteMove) {
      setIsBlackMove(false); //both isWhiteMove and isBlackMove can't be true at the same time
      var ID_whiteTimer = setInterval(()=>{
        while (prevWhiteTime>0) setWhiteTime(prevWhiteTime => prevWhiteTime-1)}, 1000);} //do countdown every sec
    // stopping a whiteTime if isWhiteMove=false
    return () => {clearInterval(ID_whiteTimer)};
  }, [isWhiteMove]); //do not rerender if thoose aren't changes

  //initialize black
  const [blackTime, setBlackTime] = useState(10*60);
  const [isBlackMove, setIsBlackMove] = useState(false);
  
  useEffect(()=>{//make a blackTime go countown and stop a whiteTime
    if (isBlackMove) {
      setIsWhiteMove(false); //both isWhiteMove and isBlackMove can't be true at the same time
      var ID_blackTimer = setInterval(()=>{
        while(prevBlackTime>0) setBlackTime(prevBlackTime => prevBlackTime-1)}, 1000);} //do countown black every sec

    // stopping a blackTime if isBlackMove=false
    return ()=> {clearInterval(ID_blackTimer)};
  }, [isBlackMove]);//do not rerender if thoose aren't changed

  return(
    <View style={styles.mainCoitainer} >
      <StatusBar hidden={true}/>
      {/* BLACK BUTTON */}
      <TouchableOpacity onPress={setIsWhiteMove(true)} style={styles.opponentButton}>
        <View>
          <Text>BLACK</Text>
          <Text style={styles.timerText}>
          {Math.floor((blackTime/(60*60))%24)}:
          {Math.floor((blackTime/60)%60)}:
          {Math.floor(((blackTime)%60))}
          </Text>
        </View>
      </TouchableOpacity>

      {buttonBar()}

      {/* WHITE BUTTON */}
      <TouchableOpacity onPress={setIsBlackMove(true)} style={styles.playerButton}> 
        <View>
          <Text>WHITE</Text>
          <Text style={styles.timerText}>
          {Math.floor((whiteTime/(60*60))%24)}:
          {Math.floor((whiteTime/60)%60)}:
          {Math.floor(whiteTime%60)}
          </Text>
        </View>
      </TouchableOpacity>

      </View>
  );
}

I use useEffect for handling changes of isWhiteMove and isBlackMove. So, probably problem is somewhere here. So, the algorithm of useEffect handling should be next. For example, black button is pressed. OnPress changes an isWhiteMove state. Changing of isWhiteMove trigger an useEffect, which make blackTime off and start whiteTime countdown. When isWhiteMove going to false, it cleans the timer and do nothing. It's how it's supposed to be. I absolutely have no idea what's going wrong.

I've found some similar questions in stackoverflow, but no one of them helped me.

UPD: as the one of probably reasons, changed a "while" to "if", but it still the same



Solution 1:[1]

your problem is while and the timer. the timer is changing its value many times in one second (that's how timers work in electronics), which causes the useffect to rerender when isBlackMove has changed.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Mehdi Khalfallah