kenodek
kenodek

Reputation: 372

How to change only a part of a state?

Is there a way to change only a part of this.state.first? Let's say the third index would be true but the rest stays as it is. I don't want to rewrite it. I thought about using Spread Sytax but I don't know how?

import React from "react";

class MyClass extends React.Component {
  constructor() {
    super();
    this.state = {
      first: [false, false, false, false, false, false, false]
    };
  }
}

Upvotes: 4

Views: 858

Answers (4)

Joe
Joe

Reputation: 86

assign first to another variable immutably then use the splice method to remove the value from a specific index, set the delete count to 1, assign a new value to that index

import React from "react";

class MyClass extends React.Component {
  constructor() {
    super();
    this.state = {
      first: [false, false, false, false, false, false, false]
    };
  }

  changeIndex = (index) => {
    this.setState(({ first }) => {
      let clone = [...first];
      clone.splice(index, 1, newValue);
      return { first: clone };
    });
  };
}

Upvotes: 0

jcgzzc
jcgzzc

Reputation: 121

I suggest you check out the immutability-helper package (docs: https://github.com/kolodny/immutability-helper), as mentioned in https://reactjs.org/docs/update.html

It will take care of making sure the new array is created, as mentioned by Chris in another answer. Without the new array, the state won't know anything changed and that it needs to update. In your case the code would look something like this:

import React from "react";
import update from "immutability-helper";

class MyClass extends React.Component {
  constructor() {
    super();
    this.state = {
      first: [false, false, false, false, false, false, false]
    };
  }

  onChange = (toggleIndex) => {
    //gets current value and uses bang (!) operator to get inverse value
    let newValue = !this.state.first[toggleIndex];

    //immutability-helper will take care of making sure the array gets updated and recreated
    let newState = update(this.state, {
            first: {
                [toggleIndex]: {
                    $set: newValue
                }
            }
        }
    );

    this.setState(newState);
  }
}

Upvotes: 2

Aldo
Aldo

Reputation: 1287

Yes, you can, and with one line:

this.setState(prevState => {
   first: [...prevState.first.slice(0,1), true, ...prevState.first.slice(3)]});

Upvotes: 0

Chris
Chris

Reputation: 59541

You can do this with:

this.setState(prevState => {
  const newFirst = [...prevState.first];
  newFirst[2] = true;
  return {first: newFirst};
});

This will yield:

[false, false, true, false, false, false, false]

As you know, you mutate the state with setState(). To change only one value in the array, we need to create a temporary copy of the array that we can work with (thatis what const newFirst = [...prevState.first] does), change the value of the wanted index (newFirst[2] = true) and then set the state to be that new array.

What is important to note here is that we did all this inside the callback function that we passed to setState(). This assures us that we are always working with the previous state, and not the current one. This is a good practise to do anytime you are setting a new state that depends on the previous state.

Upvotes: 1

Related Questions