Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React idiomatic way to update Map object in state

I'm using the Map class.

I have a state like this:

{
    rows: new Map([])
}

With each row representing an entry in a table. I'd like to update each row independently and asynchronously in a thread-safe manner.

What is the idiomatic React way to perform a setState when each modification is something like this (assume "fooId" has already been inserted into the Map):

const rows = this.state.rows;
const row = rows.get("fooId");
row.status = '75%';

this.setState({
    rows: rows
});
like image 289
Novaterata Avatar asked Jan 11 '19 19:01

Novaterata


1 Answers

The idiomatic way would be to use the functional setState() since you're updating an existing value rather than replacing it wholesale.

this.setState((prevState) => {
  const nextRows = new Map(prevState.rows)
  // Creating a new Map this way does not clone the original data
  // This means that any update to an object in the map will update the previous map.
  // To avoid this, we create a new object using object spread and assign the updated value there.
  // This has the benefit of reducing memory allocations as well, if performance is your concern.
  // Though it should not be until you have proven it to be a concern.
  const nextEntry = {
    ...nextRows.get('fooId'),
    status: '75%'
  }
  return { rows: nextRows.set('fooId', nextEntry) }
})

This is made a little easier with ImmutableJS:

this.setState(prevState => ({ 
  rows: prevState.rows.update('fooId', entry => ({ ...entry, status: '75%' }))
}))

Also, just need to contradict what @Jonas said: When you clone a map, it only clones the mapping between a key and a value of the map. It does not clone the values of the map. That means that the memory consumption required is a lot lower than you might think.

If you're sure that you won't use the old map or any of the objects referenced in the old map, you could even do away with creating a new object using object-spread and you would only shoulder the impact of copying the key/value mapping (and creating a new object). This could lead to some really confusing bugs if you're wrong (and it would be very easy to be wrong) so I would stick to the immutable thing.

If this really becomes a performance issue, you could structure your data in a different way to have even fewer allocations on change.

like image 59
Dan Avatar answered Sep 21 '22 10:09

Dan