Pickels Pickels - 1 year ago 53
Javascript Question

this.setState isn't merging states as I would expect

I have the following state:

this.setState({ selected: { id: 1, name: 'Foobar' } });

Then I update the state:

this.setState({ selected: { name: 'Barfoo' }});

Since setState is suppose to merge I would expect it to be:

{ selected: { id: 1, name: 'Barfoo' } };

But instead it eats the id and the state is:

{ selected: { name: 'Barfoo' } };

Is this expected behavior and what's the solution to update only one property of a nested state object?


I think setState() doesn't do recursive merge.

You can use the value of the current state this.state.selected to construct a new state and then call setState() on that:

var newSelected = _.extend({}, this.state.selected);
newSelected.name = 'Barfoo';
this.setState({ selected: newSelected });

I've used function _.extend() function (from underscore.js library) here to prevent modification to the existing selected part of the state by creating a shallow copy of it.

Another solution would be to write setStateRecursively() which does recursive merge on a new state and then calls replaceState() with it:

setStateRecursively: function(stateUpdate, callback) {
  var newState = mergeStateRecursively(this.state, stateUpdate);
  this.replaceState(newState, callback);