7

When I have the following initial state declared:

  getInitialState: function() {
    return {
      isValid: false,
      metaData: {
        age: 12,
        content_type: 'short_url'
      }
    };
  },

and I update state with setState like this:

...
let newMetaData = {  age: 20 };
...
this.setState({
        isValid: true,
        metaData: newMetaData
      });
...

Resulting this.state.metadata object has only age defined. But as far as I'm aware, this.setState() merges it argument to existing state. Why it's not working here, isn't this supposed to be recurrent merging?

Is there a way to merge new object properties to state object property in React/ES6?

zmii
  • 4,123
  • 3
  • 40
  • 64

4 Answers4

8

setState performs a shallow merge. If metaData is is flat:

this.setState({
  metaData: Object.assign({}, this.state.metaData, newMetaData),
});

or if using spread :

this.setState({
  metaData: { ...this.state.metaData, ...newMetaData },
});
dting
  • 38,604
  • 10
  • 95
  • 114
  • 10
    The spread operator merge isn't a "deep" merge, meaning merges are recursive. Moreover nested object properties aren't merged REF: https://davidwalsh.name/javascript-deep-merge – dodortus Mar 23 '18 at 01:32
1

Another way to approach this, if you only need to update one property, would be like this:

this.setState({
  metaData: {
    ...this.state.metaData,
    age: 20
  }
})
zero_cool
  • 3,960
  • 5
  • 39
  • 54
1

setState can also take a function, which receives an argument of state, and you can use lodash merge to do the deep merge.

  setState(state => merge(state, yourPartialObjectToBeDeepMerged));
httpete
  • 2,765
  • 26
  • 34
0

a tricky solution is here

const [complexObject, setComplexObject] = useState({a:{b:{c:1}}})
setComplexObject((s)=>{
  s.a.b.c = 2
  return {...s}
})

How does it work?

An object is a reference. If you s.a.b.c = 2, this will update the state, but the component doesn't rerender, so the dom will not change.

Then we need a way to rerender the component. If you setComplexObject(s=>s), it will not trigger rerender, because albeit the interior of the ComplexObject do change, the reference still point at the same object.

So we need ES6 spread operator to reconstruct a object by doing this {...s}

FFRfree
  • 1
  • 1