I have this state in my main parent component:
this.state = {
playableCards: [],
openedCard: null,
offeredChips: 0,
activePlayer: 0, // first player is 0, second player is 1
players: [
{
name: "player1",
remainingChips: 11,
cards: [],
score: null
},
{
name: "player2",
remainingChips: 11,
cards: [],
score: null
}
]
};
Now, I have some methods that change different properties of the state. E.g.:
takeCard = () => {
const {
activePlayer,
players,
playableCards,
offeredChips,
openedCard
} = this.state;
if(openedCard) {
// Add card to active player
let playersClone = [...players];
playersClone[activePlayer].cards = [
...playersClone[activePlayer].cards,
openedCard
];
// Add any offered chips to active player
playersClone[activePlayer].remainingChips += offeredChips;
this.setState({ players: playersClone }, () =>
this.calculateScore(activePlayer)
);
// Remove card from deck
this.setState({
playableCards: playableCards.filter(function(card) {
return card !== openedCard;
})
});
// Change active player
const nextPlayer = activePlayer === 0 ? 1 : 0;
this.setState({ activePlayer: nextPlayer });
// Reset offered chips to 0
this.setState({ offeredChips: 0 });
// Reset opened card
this.setState({ openedCard: null });
} else {
console.log("Open a card first!");
}
};
As you can see, there are many properties that are being changed just by a single click event (this method is attached to a click event). I am wondering whether is this the proper way of doing it or should I combine all the setState()
?
Its okay to call multiple setStates since React internally does batching before setState and hence will only call render
once. That said, the chances of you making a mistake in writing setState such that batching ignores a change or sets incorrect value are high(for instance you may call setState twice for the same key based on the previous value and might expect a result different from what you get). Hence its recommended that you call setState once after processing all the values
// Add card to active player
let playersClone = [...players];
playersClone[activePlayer].cards = [
...playersClone[activePlayer].cards,
openedCard
];
// Add any offered chips to active player
playersClone[activePlayer].remainingChips += offeredChips;
const playableCards = playableCards.filter(function(card) {
return card !== openedCard;
})
// Change active player
const nextPlayer = activePlayer === 0 ? 1 : 0;
// Reset offered chips to 0
// Reset opened card
// Remove card from deck
this.setState({
openedCard: null,
offeredChips: 0,
playableCards,
players: playersClone
}, () =>
this.calculateScore(activePlayer)
);