Проблема в жизненном цикле при организации пошаговой отрисовки / 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 };
}