Xeen
Xeen

Reputation: 7003

React overwrites all states on setState

I have the following setup:

this.state = {
  values: {
    id: null,
    name: "",
    unitName: "",
    unitCategory: ""
  }
};

and when I change a value in a field in a form I have the following handleChange function:

this.setState({
  values: {
    [e.target.name]: e.target.value
  }
});

the problem is - this removes all other values from the values object in my state and only leaves the one that's being modified (i.e. <input name="name" />).

How could I retain all other values?

Edit The code now looks like:

this.setState(prevState => {
  console.log(prevState.values);
  return {
    values: {
      ...prevState.values,
      [e.target.name]: e.target.value
    }
  };
});

The console.log(prevState.values) returns:

{id: 2, name: "Humidity", unitName: "himidity", unitCategory: "%"}

Which is how it should be, but when I spread it in values object, I get:

TypeError: Cannot read property 'name' of null

Upvotes: 1

Views: 2425

Answers (1)

Andrew Li
Andrew Li

Reputation: 57964

Use spread syntax to spread the other properties into state:

this.setState(prevState => ({
  values: {
    ...prevState.values,
    [e.target.name]: e.target.value
  }
}));

This also utilizes the callback with setState to ensure the previous state is correctly used. If your project doesn't support object spread syntax yet, you could use Object.assign:

values: Object.assign({}, prevState.values, {
  [e.target.name]: [e.target.value]
})

This does essentially the same thing. It starts with an empty object to avoid mutation, and copies prevState.values's keys and values into the object, then copies the key [e.target.name] and its value into the object, overwriting the old key and value pair.


Also, I'm not sure why you're doing all this:

this.state = {
  values: {
    id: this.state.values.id ? this.state.values.id : null,
    name: this.state.values.name ? this.state.values.name : "",
    unitName: this.state.values.unitName ? this.state.values.unitName : "",
    unitCategory: this.state.values.unitCategory? this.state.values.unitCategory: "
  }
};

When you set initial state in the constructor, just give the initial value, your ternary operator will never give you the true condition:

this.state = {
  values: {
    id: null,
    name: '',
    unitName: '',
    unitCategory: ''
  }
};

Upvotes: 5

Related Questions