1
votes

Introduction

I have a progress time bar on my screen which is advanced in a useEffect, inside a setInterval. The problem comes when my DB listener is triggered and executes its callback, where the code updates other states.

Code

const [isRoomFull, setIsRoomFull] = useState(false);
const [timerProgress, setTimerProgress] = useState(0);

 ...
const startGame = () => {
   ...
   advanceTimer();
}

const listenRoomChanges = (roomDoc) => {
   const { full } = roomDoc.data();

   setIsRoomFull(full);
};

const advanceTimer = () => {
  setTimerProgress(timerProgress + 1 / GAME_DURATION);
};

useEffect(() => {
    if (roomId) {
      const { firebase } = props;

      roomListener.current = firebase
        .getDatabase()
        .collection("rooms")
        .doc(roomId)
        .onSnapshot(listenRoomChanges); // <- DB listener callback
    }

    return () => {
      detachListener();
    };
  }, [roomId]);

useEffect(() => {
  if (timerProgress > 0 && timerProgress < 1) {
    // Advance the timer every second
    var timerInterval = setInterval(() => {
      advanceTimer();
    }, 1000);
  }

  return () => {
    clearInterval(timerInterval);
  };
}, [timerProgress]);

Problem

The problem is that the timerProgress value is reset every time the listener callback is executed.

For example, if I do a console.log(timerProgress) inside the listener callback

const listenRoomChanges = (roomDoc) => {
   const { full } = roomDoc.data();
   console.log(timerProgress); // <----
   setIsRoomFull(full);
};

it will show me 0, when the real value is 10 secs, for example.

My current workaround

If when updating the timer progress I do

  const advanceTimer = () => {
    setTimerProgress(
      (prevTimerProgress) => prevTimerProgress + 1 / GAME_DURATION
    );
  };

instead, the timerProgress will not be "reset" to 0 when the DB listener callback updates other states...

But for some reason, this is not working 100% well (when the DB listener callback updates other states, the timerProgress advances nStateUpdatesInTheDbListenerCallback times faster, I don't know the reason but this is happening).

Does someone know how to solve this problem? Any special hook for this? Why is this happening?

I think that I can use useRef() but this will not fire a re-render...

Thank you.

1

1 Answers

0
votes

Remove return () => { clearInterval(time interval);};

From

useEffect(() => {
  if (timerProgress > 0 && timerProgress < 1) {
    // Advance the timer every second
    var timerInterval = setInterval(() => {
      advanceTimer();
    }, 1000);
  }

  return () => {
    clearInterval(timerInterval);
  };
}, [timerProgress]);

And let me know,