Как ждать после установки состояния в react

#javascript #reactjs

#javascript #reactjs

Вопрос:

React 16.8 (с использованием классов, а не перехватов)

рассмотрим следующий if оператор в функции, которая вызывается onClick

  if (this.state.opponentIsDead) {
    this.setState({
      disableAttack: 'disabled',
    }, () => {
      this.timer = setTimeout(() => {
        this.props.postFightData({
          train_exp: 100,
          drop_chance: this.state.monster.drop_chance,
          gold_rush_chance: this.state.monster.gold_rush_chance,
          gold_drop: this.state.monster.gold_drop,
        });
      }, 1000);
    });
  }
  

Что я пытаюсь сделать, так это подождать секунду перед публикацией данных боя, если вы выиграли бой, тайм-аут сработает. Но, как вы можете видеть, я обновляю состояние, чтобы отключить кнопку.

Что я думал сделать, так это перенести время ожидания в componentDidUpdate метод, таким образом, компонент будет повторно отображаться, а кнопка будет отключена, однако я чувствую, что это неправильный способ сделать это.

Я понимаю, что вы можете обернуть setState в асинхронную функцию, но мне также интересно, лучший ли это подход.

Цель состоит в том, чтобы отключить кнопку, затем подождать 1 секунду и опубликовать данные. Какой подход лучше всего использовать?

Что не так с этим подходом?

Для тех, кто, возможно, не знает, setState будет вызван для обновления состояния, но вместо повторного рендеринга он вызовет функцию обратного вызова, таким образом, кнопка не отключается, пока таймер отсчитывает время.

он будет отключен после таймера, а не до, где, как я хочу, до, а не после.

Ответ №1:

Я подозреваю, что что-то еще вызывает у вас проблему. Похоже, этот код работает так, как вы хотите (или я неправильно понимаю).

https://codesandbox.io/s/8nz508y96j нажатие кнопки отключает кнопку, а оповещение post появляется через 3 секунды

Хотя использование componentDidUpdate является рекомендуемым подходом..

https://reactjs.org/docs/react-component.html#setstate

Второй параметр setState() — это необязательная функция обратного вызова, которая будет выполнена после завершения setState и повторного отображения компонента. Обычно мы рекомендуем использовать componentDidUpdate() вместо такой логики.

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

1. Итак, вы предлагаете перенести мое ожидание публикации в componentDidUpdate? Разве это не было бы плохо, потому что вы загрязняете его логикой, когда он должен просто установить состояние, если предыдущее состояние и / или реквизиты не соответствовали новому материалу?

2. На самом деле я просто передавал рекомендации документа tbh. Я думаю, что эта рекомендация основана на том, что лучше, чтобы ваш компонент основывал свое поведение на своем состоянии. В этом случае потребовалось бы больше логики и отслеживания состояния, как вы говорите (щелкнули ли они, был ли выполнен запрос и т.д.). Я был бы склонен оставить все как есть, пока вы не найдете причину для его изменения.

Ответ №2:

Это должно сработать.

 if (this.state.opponentIsDead) {
  this.setState({
    disableAttack: 'disabled',
  });

  window.requestAnimationFrame(() => {
    this.timer = setTimeout(() => {
      this.props.postFightData({
        train_exp: 100,
        drop_chance: this.state.monster.drop_chance,
        gold_rush_chance: this.state.monster.gold_rush_chance,
        gold_drop: this.state.monster.gold_drop,
      });
    }, 1000);
  });
}
  

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

1. Хотелось бы получить объяснение, почему это предпочтительнее других решений. Автор спрашивает, каким было бы наилучшее решение. Хотя ваше решение работает, я не знаю, является ли это «лучшим» способом сделать это. Если у вас запущено react fiber, есть вероятность, что таймер может быть запущен до обновления состояния.

2. @pkfire можете ли вы объяснить, как это работает? Почему это работает?

3. @MathewKleppin Это на самом деле не работает. disableAttack все еще не установлен