1

I want to capture the value of my state "GeoJson" at the moment M, so here is what I do:

const prevGeoJson = Object.assign({}, this.state.geoJson);
const geoJson = Object.assign({}, this.state.geoJson);
geoJson.features.push(data);

this.setState(prevState => ({
  prevGeoJson: prevGeoJson,
  geoJson: geoJson,
  currentMarker: data
}));

But then, the value of this.state.prevGeoJson has the same value than this.state.GeoJson. I guess it is a normal behaviour from Object.assign, but don't understand why, and what is the solution?

Jerlam
  • 943
  • 2
  • 12
  • 31
  • where are you checking? this.setState is async and may not be updated when you expect it to be. Solution to that is mostly to rely on lifecycle hook shouldComponentUpdate and look for nextState – Rikin May 13 '18 at 17:18
  • Hey @jeremy I think aren't doing deep copy here, since features is the same ref. If you are using something like lodash you can try using _.cloneDeep, or spread out the features array to make a copy too. – dixitk13 May 13 '18 at 17:25
  • I think that it does not matter if the state is updated or not, because I am not modifying the value of prevGeoJson state. I check the value in the render method, but why has the prevGeoJson state the next value of geoJson state ? The value of prevGeoJson should either be null or have the value of the previous geoJson state... – Jerlam May 13 '18 at 17:28

1 Answers1

1

Object.assign will only do a shallow copy of an Object. This means the features array is still mutated.

See the docs here, and read where it says Warning for deep clone. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

See this answer for help in deep cloning an object: What is the most efficient way to deep clone an object in JavaScript?

The easiest way without any form of library would be like this:

const prevGeoJson = JSON.parse(JSON.stringify(this.state.geoJson));
const geoJson = JSON.parse(JSON.stringify(this.state.geoJson));
geoJson.features.push(data);

this.setState(prevState => ({
  prevGeoJson: prevGeoJson,
  geoJson: geoJson,
  currentMarker: data
}));

This will do a deep copy of the Object, by converting it to JSON string and then converting it back to a new Object.

If you don't mind using libraries then I would suggest lodash's cloneDeep method here: https://lodash.com/docs/4.17.10#cloneDeep

I hope this helps.

TPHughes
  • 1,437
  • 11
  • 13
  • Thanks, really clear answer. I added lodash and used cloneDeep, it works well, and from what I read it is much faster than JSON.stringify... – Jerlam May 13 '18 at 18:24