18

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()?

catandmouse
  • 11,309
  • 23
  • 92
  • 150
  • i think it is ok to have multiple set state as React will wait for event handling to finish before re-rendering. https://stackoverflow.com/questions/33613728/what-happens-when-using-this-setstate-multiple-times-in-react-component – Akash Salunkhe Oct 17 '18 at 04:42
  • You might want to change the title; if I'm understanding you right you're changing multiple objects in the state, but not changing the internals of any object in the state. Which is what, to me, 'nested' implies. – Dave Oct 17 '18 at 04:54

4 Answers4

22

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)
    );
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • 4
    Upvoted for very helpful information as: `Its okay to call multiple setStates since React internally does batching before setState and hence will only call render once.` – GD- Ganesh Deshmukh Mar 02 '20 at 11:50
10

you can change multiple properties of a state like this.

this.setState({ openedCard: null, offeredChips: 0, activePlayer: nextPlayer });
Roopak Puthenveettil
  • 1,387
  • 2
  • 13
  • 27
0

you can change multiple properties of a state like this.this.setState({value1: 0, value2: 0})

0

For functional components, the basic syntax to update more than one property at once is as follows:

function handleUserData() {
  setUserData((prevUserData) => {
    return {
      ...prevUserData,
      propertyName: theValueOrVariableHere,
      otherPropertyName: theValueOrVariableHere
    }
  })
}
Adam Gonzales
  • 829
  • 7
  • 11