首页 > 解决方案 > 有没有更简洁的方法来组织这个 recoilJS 状态?

问题描述

我刚刚了解了recoilJS,并且一直在玩弄它,并且对我所做的是否被认为是“正确的”有疑问。我的代码有效,但感觉很奇怪。

我有以下 React 函数组件:

export const TimerPanel: FC = () => {
  const gameState = useRecoilValue<GameState>(HeaderAtoms.gameState);
  const timerCount = useRecoilValue(HeaderAtoms.timerCount);
  const setTimerCounter = useSetRecoilState(HeaderAtoms.timerCounter);

  useEffect(() => {
    if (gameState === GameState.IN_PROGRESS && timerCount < 1000) {
      window.setTimeout(() => {
        setTimerCounter(timerCount + 1);
      }, 1000);
    }
  });

  return <NumberPanel num={timerCount} />;
};

其中相关的原子和选择器定义为:

export const timerCount = atom<number>({
  key: 'Header.timerCount',
  default: 0
});

export const timerCounter = selector<number>({
  key: 'Header.timerCounter',
  get: ({ get }) => {
    return get(timerCount);
  },
  set: ({ get, set }, newCount) => {
    if (get(gameState) === GameState.NEW) {
      set(timerCount, 0);
    } else if (get(gameState) === GameState.IN_PROGRESS) {
      set(timerCount, newCount);
    }
  }
});

基本上,当游戏开始时,TimerPanel计时器显示的增量是1游戏进行中的每一秒。如果用户重置游戏 ( GameState.NEW),则timerCount重置为零。如果原子/选择器没有正确完成,则会出现竞争条件,即游戏状态和计时器计数将重置,但计时器仍在运行,并且仍会再更新TimerPanel一次。这就是为什么我在选择器的道具中有if块的原因。set

基本上,我担心我的timerCounter选择器是状态的美化过滤器/直通实体,timerCount我想知道是否有更好的方法来处理这个用例。

标签: recoiljs

解决方案


如果您关心的是竞争条件,那么在您的代码中,我看不到您的计时器将如何单击。setTimeout 将打勾一次。

无论如何,您有 2 个状态,游戏状态和计时器状态。您想在游戏状态发生变化时重置计时器。在游戏状态选择器中这样做怎么样?或者将逻辑移动到自定义钩子中并直接对这两种状态进行操作。


推荐阅读