Reputation: 850
I'm working on a small application with which you can keep track of some game scores.
The game is played between two players. A player can score points but can also incur a penalty. Instead of substracting the penalty from the player's score, it gets added to his opponent's score. The opponent should also get the next turn.
I setup a demo that implements the above description: https://codepen.io/anon/pen/ybLQvR
As you can see in the demo it doesn't quite work: when a player incurs a penalty he gets awarded the penalty, instead of his opponent.
This is due to setState
within setTurn
not being processed immediately. setScore
still uses the 'old' state in which turn has not been updated.
I'm aware this can be handled by passing a callback to setState
instead of an object (see the commented code), which takes in the previously set state. If I do that things work as expected.
However, I need the updated value of state (in this case this.state.turn
) in the addScore
outside of the setState
call as well. How would I achieve this? I've tried this.forceUpdate()
to no avail.
Should I wrap the entire function body of addScore
in the setState
callback? How would I then return any calculations based on this.state.turn
from the addScore
method should I need it?
Side question: why doesn't this.forceUpdate()
work? Does it just trigger re-rendering the component without processing the state queue?
Thanks for helping me out!
Upvotes: 0
Views: 375
Reputation: 14417
I see what you're saying now. To my undestanding what you are trying to do is make sure that the setState method has been executed before another setState method.
Now the docs have this to say on the matter:
The second parameter is an optional callback function that will be executed once setState is completed and the component is re-rendered. Generally we recommend using componentDidUpdate() for such logic instead.
So by their recommendations you should use componentDidUpdate()
. So how is the question now.
componentDidUpdate(prevProps, prevState)
That is the method signature. So we can see here that the previous state gets passed in, and we now have access to the current state via this.state
.
See codepen for the answer.
Basically - I turned the addScore
and changeTurn
into functions that were just snippets of the setState
. This means we can combine them together with or state changes to make one atomic operation. And they can be reused without adding complicated default parameters for different scenarios.
Secondly, I added in functions which applied these methods in order to set the state. These are what the buttons use!
Finally in the componentDidUpdate
function there is now a chance to apply actions based on the current action that is being executed. Do not add a setState for the default action, otherwise you'll get an infinite loop of updating......
Upvotes: 1