ReactJS. функция вызывается до обновления состояния

#reactjs #asynchronous #setstate

#reactjs #асинхронный #setstate

Вопрос:

Я пишу приложение Snake game для практики.

У меня есть функция changeDirection, которая задает соответствующее направление в состояние на основе щелчка стрелки:

 changeDirection = event => {
  const { direction } = this.state;

  const keyPressed = event.keyCode;

  if (keyPressed === keyCodes.LEFT_KEY amp;amp; direction !== "right") {
    this.setState({ direction: "left" });
  }
  if (keyPressed === keyCodes.UP_KEY amp;amp; direction !== "down") {
    this.setState({ direction: "up" });
  }
  if (keyPressed === keyCodes.RIGHT_KEY amp;amp; direction !== "left") {
    this.setState({ direction: "right" });
  }
  if (keyPressed === keyCodes.DOWN_KEY amp;amp; direction !== "up") {
    this.setState({ direction: "down" });
  }
}
  

и это работает нормально, но проблема в другой функции.
Я обновляю положение головы змеи на основе состояния направления. и эта функция выполняется каждые 1 секунду (с setInterval), и при изменении направления голова змеи не меняет свое направление сразу. Она выполняет это на следующем шаге.

Я понимаю, что это потому, что состояние нового направления еще не установлено, когда snake перемещается в первый раз, но я не знаю, как это исправить.

вот репозиторий:https://github.com/Dito-Orkodashvili/snake

Комментарии:

1. Пожалуйста, включите весь соответствующий код. Невозможно сказать, что может быть неправильным из кода, который в данный момент находится в вашем вопросе.

2. Я добавил ссылку на репозиторий в исходное сообщение.

Ответ №1:

Вы можете использовать это.

    this.setState({ direction: "down" },anotherFunction());
  

Вызовите вашу функцию в обратном вызове setState, она будет вызвана после обновления состояния.

ссылка:https://medium.learnreact.com/setstate-takes-a-callback-1f71ad5d2296

Комментарии:

1. Это кажется правильным.. Хотя, если его функция вызывается каждую секунду с помощью setInterval , код должен просто работать: 1) changeDirection() изменяет состояние. 2) В конечном итоге, setInterval вызовет функцию changeHeadPosition() , и это будет после (1) точки. Итак, я не знаю, почему у него проблема.. @Dito Возможно, вам следует показать и другую функцию

2. Я знаю это, но проблема в том, что я вызываю эту ‘AnotherFunction’ в другом месте. p.s Я поместил ссылку на репозиторий целиком в исходное сообщение

3. Это должно быть this.setState({ direction: "down" }, anotherFunction); , если AnotherFunction не возвращает функцию

Ответ №2:

Вы обновляете состояние только направления. Это приводит к повторному отображению компонента. Затем вы обновляете состояние змеи, и компонент повторно визуализируется снова, а затем, когда вы видите, что заголовок обновлен.

Решением могло бы быть отключение функции moveSnake. Используйте moveSnake только для перемещения змеи после рендеринга компонента.

Создайте другую функцию для обновления состояния head и snake и вызовите ее из обработчика событий клавиатуры. Таким образом, компонент будет повторно отображать все изменения состояния одновременно.

Обновление состояния из setInterval также должно работать, например:

 newDirection;

startGame = () => {
   this.interval = setInterval(() => {
     this.moveSnake();
   }, 200);
};

changeDirection = event => {
    const keyPressed = event.keyCode;

    if (keyPressed === keyCodes.LEFT_KEY amp;amp; direction !== 'right') {
      this.newDirection = 'left';
    }
    if (keyPressed === keyCodes.UP_KEY amp;amp; direction !== 'down') {
      this.newDirection = 'up';
    }
    if (keyPressed === keyCodes.RIGHT_KEY amp;amp; direction !== 'left') {
      this.newDirection = 'right';
    }
    if (keyPressed === keyCodes.DOWN_KEY amp;amp; direction !== 'up') {
      this.newDirection = 'down';
    }
};

moveSnake = () => {
   /* do updates in the snake shape */

   this.setState({
     direction: this.newDirection,
     snake: copyOfSnake
   });
};
  

Комментарии:

1. Это именно то, что происходит, но я думаю, что ваше решение не подходит для моего случая. Потому что я обновляю положение головы snakes каждую секунду с использованием setInterval. Вот как движется змея. она сдвигает начало на одну ячейку вперед и удаляет хвост. итак, если я вызываю эту функцию только в событии нажатия клавиши, то змея не будет двигаться, пока я не нажму кнопку. поправьте меня, если я ошибаюсь.

2. Тогда решением могло бы быть не обновлять состояние напрямую из обработчика событий, а сохранить значение направления. Затем обновите состояние из setInterval, используя вашу переменную direction.