React - Using setState() for a 2D Array

Been banging my head on this one for a while now. I’m trying to build a simple React game with Merge-3 mechanics. It’s a 5x5 grid, and I’ve set up my state like this:

this.state = {
            boardState: [
                [1,0,0,0,0],
                [2,0,0,0,0],
                [3,0,0,0,0],
                [4,0,0,0,0],
                [5,0,0,0,0]
            ]
        }

I’m not 100% sure that a nested array is the best way to handle this data, but I’m gonna stick with it for the time being.

Anyway, now the handleClick function:

handleClick (event) {
        const rowindex = parseInt(event.target.getAttribute('rowindex'));
        const tileindex = parseInt(event.target.getAttribute('tileindex'));
        const tileText = this.state.boardState[rowindex][tileindex];
        console.log('tile value: ', tileText);

        this.setState(state => {
            const row = state.boardState.map((row, i) => {
                let tile;
                if (i === rowindex) {
                    tile = row.map((cell, j) => {
                        if (j === tileindex && tileText === 0) {
                            
                            return cell + 1;

                        } else { return cell; }
                    }); 
                    
                    return tile;

                } else { return row; }
            });
      
            return {
                row,
            };
        });
    };

It almost works, but it isn’t actually updating the state and I’m not sure why. When I was testing it with a simple array, it worked perfectly. I have fiddled with values, trying to return different things, but I can’t get it working.

I’m sure I’m missing something obvious, but any help would be appreciated.

This doesn’t really look right, can you explain what is supposed to happen to the tile value when it’s clicked – what should it update to? 2D array is fine, but the logic looks all wrong at the minute.

Edit: This should do what the above code is trying to do (sorry, not tested, parentheses may not quite be balanced). Your logic says if a user clicks a cell/tile/whatever you call it, if the value is 0, add 1, any other value and just return that value, so:

this.setState(({ boardState }) => ({ boardState: 
  boardState.map((row, i) => {
    row.map((tile, j) => {
      if (i === rowIndex && j === tileIndex && tile === 0) {
        return 1;
      } else {
        return tile;
      }
    });
  });
}));

Wow I overcomplicated that. I’ll have to test your code tomorrow, but it looks like it’s exactly what I need.

Now I just have to figure out the best way to handle the heavy gaming logic of finding and merging numbers…

1 Like

I tried the function you wrote, @DanCouper, but it’s still not updating state.

handleClick (event) {
        const rowindex = parseInt(event.target.getAttribute('rowindex'));
        const tileindex = parseInt(event.target.getAttribute('tileindex'));
        // const tileText = this.state.boardState[rowindex][tileindex];

        this.setState(({ boardState }) => ({ boardState: 
            boardState.map((row, i) => {
              row.map((tile, j) => {
                if (i === rowindex && j === tileindex && tile === 0) {
                    console.log(i, rowindex, j, tileindex, tile);
                    return 1;
                } else {
                    return tile;
                }
              });
              // warning said I wasn't returning in all cases, so I added this
              return row;
            })
        }));
    };

Your version looks exactly like what I had before when I was first using a simple array, and it worked fine then. Once I switched to a 2D array, it’s been a hassle.

I think I should probably rethink my state object, but now I’m determined to figure out why this isn’t working. Any ideas?

EDIT: Got it! I just needed to stop returning the original row because it was undoing all the changes the .map()s were making. I added:

let newRow = row.map((tile, j) => ({ .... });

and then just returned newRow instead of row. It’s working. Thanks for straightening me out!

1 Like