0

Given this 2d array React state,

this.state =
  board: [
    [null, null, null, null],
    [null, {id: 21, canSelect: false}, null, null],
    [null, {id: 42, canSelect: false}, null, null],
    [null, null, null, null]
  ]
}

I have 3 main questions regarding using setState to update this state:

1) How would I target a specific index within this 2d array state in React? Something like board[1][1]: {newObject}?

2) How would I update only the "canSelect" values for each?

3) If there were an unknown number of array indexes I would need to update (say between 2 and 8), how would I update only those indexes?

Any help is really appreciated :)

damon
  • 2,687
  • 8
  • 25
  • 35

1 Answers1

1

1) How would I target a specific index within this 2d array state in React?

To access let's say, the object with id = 21 do that:

console.log(this.state.board[1][1].id)

2) How would I update only the "canSelect" values for each?

To change a specific canSelect property do it in a immutable way:

onChange = e => this.setState(state =>({
    ...state,
    board : state.board.map((arr, i) => arr.map((item,j) =>{
        if(!item.hasOwnProperty('canSelect') return item
        return {...item, canSelect: !state.board[i][j]}
    }))
}))

If there were an unknown number of array indexes I would need to update (say between 2 and 8), how would I update only those indexes?

If you want non-consecutive arrays(sparse), just create an Object and then map it's keys instead of indexes:

const obj = {myKey : 'foo'}
console.log(obj.myKey) //foo

See more about sparse arrays in this question, but the gist here is do not use it, even if they do not take up more space than a "normal" array, what you really want is a hashing mecanism that map key names to values, good old JSON

Update

Based on your comments I've realized that I misunderstood the third problem, but I'm not excluding it cause it can be useful.

So let's assume you want to update the canSelect property on every id contained in a list:

const idsToUpdate = [1,22]

But you don't know if the given ids exist on your current collection, the solution would be iterate through every item, check if they aren't null, then check if the id is inside the idsToUpdate list and only then update the canSelect property:

this.setState(state =>({
    ...state,
    board : state.board.map((arr,i) => arr.map((item, j) =>{
        if(!item) return item
        if(!idsToUpdate.includes(item.id)) return item
        return {...item, canSelect: true}
    }))
}))
Dupocas
  • 20,285
  • 6
  • 38
  • 56
  • Thank you for this, especially for answer #2. I too often forget how useful the spread operator can be. For #3, I have a clarifying question. Im not exactly certain how using an object would help me update the state of an unknown number of indexes. Or are you suggesting that using a 2d array here in the first place is not the best way to go about it? – damon Jul 22 '19 at 14:28
  • I'm sorry, I perhaps misunderstood your question. You want to know how to update an unknown number of indexes? – Dupocas Jul 22 '19 at 14:34
  • No worries, I'll try to clarify. In this 4x4 2d array, there are 16 indexes. Let's say 8 of them have been set to objects instead of `null`. Based on user input, I would have to update the `canSelect` value of only 5 of them (but could have been anywhere between 2 and 7, since it is user determined). I would want to update only those user-selected 5 indexes, and not any others – damon Jul 22 '19 at 14:40
  • 1
    Thanks for your correction, and for your swift answer in general. My two main take aways from your answer are 1) I had seen the spread operator used in `setState` before, but I never understood the practical application until now. And 2) I wasn't aware that I could perform such complex `map` and conditional statements when setting the value. Thanks again :) – damon Jul 22 '19 at 15:22