mehulmpt
mehulmpt

Reputation: 16547

React: Update nested state?

I'm using react native. Suppose I've this state:

{
persons: [{
  name: "Person",
  id: 0,
  value: "",
  percent: 50,
  messed: false
},
{
  name: "Person",
  id: 1,
  value: "",
  percent: 50,
  messed: false
}]
}

I want to update, say, percent of id 1. How do I do it with this.setState? I can deep clone persons object every time and update it but I need to do it a lot of times and the persons object is quite large anyway so it's not performance-wise efficient.

Currently I'm doing

this.state.persons[id].percent = 0;
this.forceUpdate();

which seems not so react-ish. How do I go about this?

Upvotes: 0

Views: 3992

Answers (4)

Pei Han
Pei Han

Reputation: 156

another way to change the state, but flatten state by person id maybe the better option.

 state = {
       persons: [{
          name: "Person",
          id: 0,
          value: "",
          percent: 50,
          messed: false
        },
        {
          name: "Person",
          id: 1,
          value: "",
          percent: 50,
          messed: false
        }]
 }

 this.setState(({persons}) => {
   persons
     .filter(i => i.id === 1)
     .map(i => i.percent = 0)
 })}

Upvotes: 0

Sasang
Sasang

Reputation: 1281

You shouldn't be updating the state directly as react mentions several time in their docs. An option you can use is the spread oeprator (or Object.assign):

let newPersonsList = [...this.state.persons];
newPersonsList[2] = {...newPersonsList[2], percent:0};
this.setState({persons:newPersonsList});

Note spread operators only go 1 level deep in copying arrays, i believe, so you are taking the same references for all the persons objets and placing them in a new array. Then you are creating a new object with an updated percent property and assigning it to replace an old reference. Performance wise this should be quick, since no extensive deep copy occurs.

Alternately if you find yourself having a lot of nested objects needing to be updated, i would suggest you take a look at the following library: immutability-helper. Its specifically designed for such cases.

Upvotes: 3

samanime
samanime

Reputation: 26527

You would have to update the whole state, pretty similar to what you're doing. However, instead of using this.forceUpdate(), I'd recommend calling this.setState({ persons: this.state.persons }).

What you may want to do is consider flatting out your persons into the state. You could do something like create a unique key for each based on their index. So, index of something like this:

const persons = getPersonsData();
this.setState({ persons });

Instead do something like this:

const persons = getPersonsData();
this.setState(persons.reduce((result, person, index) => Object.assign(result, { [`person${index}`]: person }));

The persons.reduce bit will take your array and create an object like this:

{
    person0: {},
    person1: {},
    person2: {}
}

Then, each person will be flat in the state so you can just update it more directly. Not a huge difference, but depending on your use-case, could be worthwhile.

Upvotes: 1

Moe
Moe

Reputation: 3713

I would just use setState. Let React worry about the performance optimizations

   this.setState(object.assign({}, this.state, 
      this.state.persons.map(p => {
        if (p.id === id) p.percent = 0;
      }
   )))

Upvotes: 0

Related Questions