0

I am a React beginner, trying to make a card game app (using 'react-dnd' for drag and drop functionality).

The board state (where the cards are placed) of this app is a 4x4 grid, stored as a 2d array

(Initial examples are truncated)

this.state = {
      board: [
        [null, null, null, null],
        [null, null, null, null],
        [null, null, null, null],
        [null, null, null, null]
      ]
};

When cards are placed onto a space, this setState function is called (using immutability-helper):

// 'bxy' is an object containing x & y position of board to find position
// 'player' is string of either 'p1' or 'p2' to figure out which player just played the card
// 'id' is unique integer of card to provide more card information
this.setState(
      {
        // add new card to board
        board: update(this.state.board, {
          [bxy.x]: { [bxy.y]: { $set: { id, player, x, y } } }
        })
      },
      // callback to run game logic based on newly placed card
      this.runAfterSetState(player, bxy, id)
    );

// Board would look something like this after first card placed:
// board: [
//   [null, null, null, null],
//   [null, {id: 3, player: "p1", x: 1, y: 1}, null, null],
//   [null, null, null, null],
//   [null, null, null, null]
// ]

That setState calls a callback function runAfterSetState to run actual game logic information based on the card that was just played. Inside that function is another setState call. This setState would happen only under a specific instance where, if there are multiple enemy cards, a player needs to now click on one of those enemy cards. I think, in order to achieve this, I needed to add a new object key to the enemy card information in board state (so that I can then add styles, clickHandlers, etc). I think this is where things are going wrong.

if (enemyCards > 1) {

      // new object key to add
      let objToAdd = { waitingToBeSelected: true };

      // update card object in board state with new object above
      enemyCards.map(card => {
        this.setState({
          board: update(this.state.board, {
            [card.x]: { [card.y]: { $merge: objToAdd } }
          })
        });
      });

      // this shows the correctly updated information
      console.log(this.state.board);
}

While that console log above seems to show that the information is correctly updated, the program does not actually reflect this (using the React inspector Chrome tool). I suspect my program is re-rendering the Board component again without this newly updated information, essentially erasing it? As far as I can tell, this code block above should be the last thing that is called, and thusly should be what the component state is at the end.

Any help here would be greatly appreciated.


Codesandbox with full working code (and my dumb comments):

https://codesandbox.io/s/billowing-leaf-81hw9?fontsize=14

To see my specific issue, one colored card must have 2 or more arrows touching adjacent enemy cards arrows. Example image: https://i.stack.imgur.com/hlJUA.png (Red Card's Top Left and Left arrows are touching enemy Blue Cards arrows)

damon
  • 2,687
  • 8
  • 25
  • 35
  • 1
    Is there a better way to share React component code on StackOverflow...? Yes, create a snippet in [codesandbox](https://codesandbox.io/) and choose React app – Radonirina Maminiaina Jun 25 '19 at 18:20
  • Most likely what you want to do is, instead of having two `setState` calls, your logic would update a single plain object, and then at the end you would do one `setState` using that object – Austin Greco Jun 25 '19 at 18:43
  • Thank you @RadonirinaMaminiaina, codesandbox link has been added. – damon Jun 25 '19 at 18:45
  • @AustinGreco I suppose my issue is that the second `setState` call will be called very rarely, as this is almost an edge case scenario. So the first one would need to be called in order for the second one to even know if it needs to be called, if that makes sense? – damon Jun 25 '19 at 18:51

0 Answers0