首页 > 解决方案 > 当侦听器回调更新状态时,React useState(prevState => ...) 不起作用

问题描述

介绍

我的屏幕上有一个进度时间栏,它在 setInterval 内的 useEffect 中高级。当我的数据库侦听器被触发并执行其回调时,问题就出现了,代码更新其他状态。

代码

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]);

问题

问题是每次执行侦听器回调时都会重置 timerProgress 值。

例如,如果我在侦听器回调中执行 console.log(timerProgress)

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

例如,当实际值为 10 秒时,它将显示 0。

我目前的解决方法

如果在更新计时器进度时我会

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

相反,当 DB 侦听器回调更新其他状态时, timerProgress 不会“重置”为 0...

但是由于某种原因,这不能 100% 正常工作(当 DB 侦听器回调更新其他状态时,timerProgress 提前nStateUpdatesInTheDbListenerCallback时间更快,我不知道原因,但这种情况正在发生)。

有人知道如何解决这个问题吗?有什么特殊的钩子吗?为什么会这样?

我认为我可以使用 useRef() 但这不会触发重新渲染...

谢谢你。

标签: javascriptreactjsreact-native

解决方案


消除 return () => { clearInterval(time interval);};

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

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

让我知道,


推荐阅读