mieradi
mieradi

Reputation: 17

React: In state, how would I update a nested object at a certain index?

How would I update values of single events using setState? Also happy to see how it's done outside React.

state = {events: [{
  event1:{
    name: 'Name 1',
    id: 1,
  },
},{
  event2:{
    name: 'Name 2',
    id: 2,
  },
},{
  event3:{
    name: 'Name 3',
    id: 3,
  },
}]}

Upvotes: 0

Views: 215

Answers (4)

coreyward
coreyward

Reputation: 80060

Since your top-level state property (events) is an array, you can manipulate the value and call setState({ events: yourUpdatedEventsArray }).

Because setState is asynchronous, you will want to do this using the setState callback:

setState(prevState => {
  const updatedEvents = prevState.events.map(event => {
    # update and return `event` as needed
  })

  return { events: updatedEvents }
})

If you weren't passing this back to React, you could modify the array in place using findIndex and then array[index].name = "foo", but you don't want to mutate the state directly with React.

Upvotes: 0

Sven Tschui
Sven Tschui

Reputation: 1435

As @Oleksandr Kovpashko mentioned you can use .map since it creates a new array.

You can also use .slice() to clone the array and then mutate it. Note that it only clones the array, not the items. You should NOT mutate items:

const arr = ['one','two','three','three','five'];
const clone = arr.slice()

clone[3] = 'four';

console.log(clone);

Upvotes: 1

skyboyer
skyboyer

Reputation: 23705

for current structure only Array.map can help. But I can see id field inside. So how about changing structure to having object?

{
 1: {
   event1:{
    name: 'Name 1',
    id: 1,
   },
  },
 2: {
   event2:{
    name: 'Name 2',
    id: 2,
   },
 },

Then you would get power of spread operator:

this.setState(prevState => ({
    ...prevState.events,
    [idToReplace]: {
        ...prevState.events[idToReplace],
        name: 'new name',
    },
}));

Also I wondering if it make sense to have so deep nesting in single element. Maybe it'd better to deal with name of specific event inside of child component.

Upvotes: 1

Oleksandr Kovpashko
Oleksandr Kovpashko

Reputation: 800

You can do it using Array.map method:

renameEvent(idToRename, newName) {
  this.setState(prevState => ({
    events: prevState.events.map(event => {
      if (event.id === idToRename) {
        return {...event, name: newName};
      } else {
        return event;
      }
    });
  })); 
}

Upvotes: 1

Related Questions