У меня следующая ситуация в интерфейсе настольной игры на основе React.
У меня есть обработчик событий, который обновляет состояние, когда игроки делают ход:
const move = ...
this.setState(function (state, _props) {
return this.apply_move(state, move);
});
apply_move(state, move) {
let board_copy = _.cloneDeep(state.board);
// applies the move to board_copy somehow
...
return {
board: board_copy,
};
}
Затем я хочу сначала визуализировать свое движение, а затем запустить ИИ, чтобы произвести движение для бота: вызов этой функции занимает несколько секунд, пока ИИ вычисляет свое движение. На самом деле это вызов функции WebAssembly.
Я помещаю запрос на перемещение ИИ в componentDidUpdate
:
componentDidUpdate(prevProps, prevState) {
if (this.state.history.length > prevState.history.length) {
if (this.botHasToMove()) {
this.getMoveFromBot(); // <--- this runs for 5 seconds
}
}
}
Я ожидаю, что это будет выполняться после вызова render
, поэтому я сначала увижу, как отрисовывается мой ход, а затем будет пауза на пару секунд, пока ИИ вычисляет, а затем должен отрисовываться ход ИИ.
Однако проблема в том, что хотя я вижу, что render
вызывается в консоли перед запросом перемещения ИИ, и я вижу, что состояние было обновлено с моим перемещением, но сама DOM не обновляется. Он обновляется только тогда, когда длинный вызов для получения движения ИИ завершен и происходит еще одно render
. Затем оба движения отображаются одновременно, и я могу видеть их в браузере.
Я ожидал, что каждый вызов render
должен обновлять DOM (если там что-то изменилось, а в моем случае это было), но по какой-то причине обновление DOM не происходит.
Если я не вызываю длинный вызов ИИ в componentDidUpdate
, все работает нормально, и я вижу эффект от первого render
.
Может кто-нибудь объяснить, почему это происходит, и научить меня, как правильно принудительно обновить DOM при первом вызове render
?
render
был вызван и завершен, в браузере не было изменений для фактического обновления DOM. - person dying_sphynx   schedule 13.06.2020setTimeout(() => this.getMoveFromBot(), 10);
вместоthis.getMoveFromBot()
вcomponentDidUpdate
выше. По-видимому, перерыв в 10 мс (или даже 1 мс) дает ему возможность обновить DOM. - person dying_sphynx   schedule 13.06.20200
) работает, потому что оно перемещает результирующее обновление состояния в обратный вызов, помещенный в конец очереди событий, чтобы все обновления в очереди из текущего цикла рендеринга могли обрабатываться и повторно рендериться. Я уверен, что вы можете добиться того же более правильным образом, используя значение состояния, чья очередь это, и реализовывать каждый ход с помощью функции жизненного циклаcomponentDidUpdate
. - person Drew Reese   schedule 14.06.2020this.botHasToMove()
, которая проверяет, что вы называете, чья сейчас очередь (она проверяет логическое значение изthis.state
), и я помещаю запрос на ход ИИ вcomponentDidUpdate
(как вы можете увидеть в исходном вопросе). Не совсем уверен, как это концептуально отличается от того, что вы предлагаете... - person dying_sphynx   schedule 14.06.2020componentDidUpdate
? Ходы человека и ИИ сильно различаются: ходы человека создаются в обработчике событий, который просто обычно обновляет состояние. А повороты ИИ создаются длительным вызовом WebAssembly, который должен вызываться в какой-то момент сразу после получения и рендеринга движения человека. - person dying_sphynx   schedule 14.06.2020