Reputation: 1166
I have the following situation in my board game interface based on React.
I have an event handler which updates state when players makes a move:
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,
};
}
Then I want to first render my move and then run the AI to produce a move for the bot: this function call takes several seconds while AI is calculating its move. It's actually calling a WebAssembly function.
I put the request for AI move in componentDidUpdate
:
componentDidUpdate(prevProps, prevState) {
if (this.state.history.length > prevState.history.length) {
if (this.botHasToMove()) {
this.getMoveFromBot(); // <--- this runs for 5 seconds
}
}
}
I expect that this will run after the call to render
, so I will first see my move rendered and then there will be a pause for a couple of seconds while AI is calculating and then AI move should be rendered.
However, the problem is that even though I see render
called in the console before requesting AI's move and I can see that the state was updated with my move, but the DOM itself is not updated. It is only updated when the long call to get AI move is completed and one more render
happens. Then both moves are rendered simultaneously and I can see them in the browser.
I would expect that each call to render
should update the DOM (if there something had changed, and in my case it had), but for some reason the DOM update doesn't happen.
If I don't invoke the long call to AI in componentDidUpdate
everything is working fine and I can see the effect of the first render
.
Could somebody please explain why is this happening and teach me what is the proper way to force update of the DOM in the first render
call?
Upvotes: 1
Views: 227
Reputation: 1652
I love the questions you have made, because I like this kind of problem, your actually doing great with your code, but there's a problem with your code, you actually mention a long call or long execution code, JS run in a single thread, that means that all the processes runs in just one channel (thread), so i would highly recommend you to watching these two videos, about Event Loops in JS, it's the reason for your problem:
How works Event Loops JS - JSConf.Asia
How works Event Loops JS - JSConf EU
the short answer for your problem it's that you are blocking the thread execution in JS, I mean all the JS execution is executing sequentially in a "execution queue", so the next execution code won't execute until the previous ones got finished.
So how you can fix this ? to avoid blocking your thread, you need to execute your code in another thread, but JS is just a one thread execution language, so you really need something called WebWorkers, they allow you to run code in another "thread", so your problem is that you are blocking you execution queue, because of a long execution function is taking too long to be resolved.
I hope this can help you a lot and help you to understand how JS Event loops / execution queue works.
Upvotes: 1