Dimitry Ivashchuk
Dimitry Ivashchuk

Reputation: 625

Updating state as a nested object

I have this type of state in my app

state = {
  abc: true,
  array: [
    { id: 12345, done: false },
    { id: 10203, done: false },
    { id: 54321, done: false }
  ]
}; 

I am looking for a solution to the following problem: I need to change done property accordingly to passed id like in the following function when something like this handle(12345) is passed as an argument to handle function :

  handle = id => {
  this.state.array.map(e => {
    if (e.key === id) {
      this.setState({array: [
        { id: id, done: true },
        { id: 10203, done: false },
        { id: 54321, done: false }
      ]})
    }
  });
};

In simple words I need to change just one object in array based on provided id.

Thanks for any help or tips!

Upvotes: 1

Views: 75

Answers (4)

Aegletes
Aegletes

Reputation: 490

var newArray = this.state.array;
  for(var i = 0; i < newArray.length; i++){
      if(newArray[i].id === 12345) {
        newArray[i].done = true;
      }
  }

  this.setState({array: newArray});

By creating the newArray here you will be avoiding directly touching the state element, so you can change anything you want inside it afterwards you can set the state.

Upvotes: 0

sleighty
sleighty

Reputation: 1075

You can use this Redux pattern to return a new array with the element in question being changed, while keeping your array immutable:

handle = id => {
  const updatedArray = this.state.array.map(e => {
    if (e.key === id) {
      return { id: id, done: true };
    }
    else {
      return e;
    }
  });
  this.setState({array: updatedArray});
};

This keeps your data structures immutable while changing only what you need to change.

Upvotes: 1

skyboyer
skyboyer

Reputation: 23705

Once you are allowed to restructure state to be hashmap instead of array:

state = {
  abc: true,
  array: {
    12345: { done: false },
    10203: { done: false },
    54321: { done: false }
  ]
}; 

then you will be able to use power of spread operator:

let id = 12345;
this.setState({
    array: {
        ...this.state.array,
        [id]: {
            ...this.state.array[id], 
            done: true
        }
    }
});

Otherwise using array.map() seems to be the only option

Upvotes: 3

Arup Rakshit
Arup Rakshit

Reputation: 118261

I'd write the handle method as:

handle = id => {
  this.setState(prevState => {
    const { array } = prevState;
    return {
      array: [
        ...array.filter(o => o.id !== id),
        {id, done: true}
      ]
    };
  });
};

The idea here is that, remove the matching id from old state, and then add a new object to the array with id and done property as {id, done: true}.

Upvotes: 4

Related Questions