Проблема в жизненном цикле при организации пошаговой отрисовки / React-Hooks

Task:

Есть поле (грид) по которому двигается голова змейки, при нажатии на стрелки голова меняет направление. Рендер должен происходить согласно начальной скорости (а так же может меняться в зависимости от условий, не входит в контекст этого запроса), скорость исчисляется в секундах/миллисекундах. Весь код работает отлично за исключением проблемы (метод GameSleep) с управлением этой самой задержки рендера до следующего шага (рендера).

Кто может помочь с настройкой жизненного цикла удовлетворяющего исходной задаче?

[![введите сюда описание изображения][1]][1]

п.с. Прошу прощения за длинный листинг, не удалось спрятать в спойлер

CODE

Index.js:

ReactDOM.render(<Provider store={store}><Snake/></Provider>, document.getElementById('root'));

Snake.js:

const Snake = (props) => {
  const [process, setProcess] = useReducer(
    ReducerProcess, {start: false, victory: false, gameover: false, reset: true }
  );
  const [direction, setDirection] = useState(undefined);
  
  const SnakeEventListener = useCallback((event) => {
    if( checkKey(event.code) ) {
      const direction = getDirection(event.code);
      setDirection(direction);
    }
  }, []);

  const onProcess = useCallback((inType) => {
    switch(inType) {
      case STATE.reset:
        setDirection(undefined); break;
      case STATE.start:
        document.addEventListener('keydown', SnakeEventListener, false); break;
      case STATE.victory:
        document.removeEventListener('keydown', SnakeEventListener, false); break;
      case STATE.gameover:
        document.removeEventListener('keydown', SnakeEventListener, false); break;
      default: break;
    }
    setProcess({type: inType});
  }, [SnakeEventListener]);

return (
<div>
 <Grid process={process} toProcess={onProcess} direction={direction} toDirection={setDirection}/>
 <button onClick={()=>onProcess('reset')}>Reset</button>
 <button onClick={()=>onProcess('start')}>Start</button>
</div>
);
}

Grid.js:

const Grid = (props) => {
  const {process, toProcess, direction, toDirection} = props;
  const [snake, setSnake] = useState(undefined);
  const [grid, setGrid] = useState(undefined);

  // Effect => Initial
  useEffect(() => {
    const Initial = () => {
      setSnake( initSnake() );
      toDirection( initDirection() );
      setGrid( InitGrid() );
    }
    if(process.reset && !direction) { Initial(); }
  }, [process, direction, toDirection]);

  // Effect => Game Loop
  useEffect(() => {
    const GameLoop = () => {
      const build = BuildGrid(snake, direction);
      if(build.victory || build.gameover) {
        if(build.victory) { toProcess('victory'); }
        if(build.gameover) { toProcess('gameover'); }
      }else{
        setSnake(build.snake);
        setGrid(build.grid);
      }
    }
    if(process.start && direction) { GameLoop(); }
  }, [process, toProcess, direction, snake]);

  return (<div>{ Cells(grid) }</div>);
}

Building.js:

const BuildGrid = (input) => {
  const content = Execute(input);
  return content;
}

const Execute = async (input) => {
  await GameSleep(input.speed);
  let newSnake = input.snake;
  … … …
  return { snake: newSnake, victory: victory, gameover: gameover };
}

const GameSleep = async (delay) => {
  return new Promise(resolve => setTimeout(resolve, delay));
}

UPDATE

теперь GameSleep синхронный, никаких асинков нету

Building.js:

const BuildGrid = (input) => {
  const content = Execute(input);
  return content;
}

const Execute = (input) => {
  GameSleep(input.speed);
  … … …
  … … …
  return { snake: newSnake, grid: newGrid, victory: victory, gameover: gameover };
}

Ответы (0 шт):