[Solved] MongodDB database stores prior values of states instead of current values

Hi, I am making a app which stores most of its values in states. Now I want to store those states in a MongoDB database and I am having some issues. When i save the array which should contain the values of states, it saves the prior values of the states and only after saving 2 times does the value change to the current one. So for example if I change the state zoom from 100 to 200 and then save, the 100 will be stored in the database and only after saving a second time does it change to 200.

Here is the function where I set the array I am going to save in the database to be equal to various states:

save() {
this.setState({fractalvalues: [this.state.width, this.state.height, this.state.iterations, this.state.zoom, this.state.panx, this.state.pany, this.state.color]})
SavedFractals.insert({
fractalvalues: this.state.fractalvalues,
createdAt: new Date(),
});
}

Here is where I set the states values from the HTML field:

handleChange(event) {
this.setState({[event.target.name]: event.target.value});
this.setState({generate: true});
}

Here is a example of a input field:


here is the input field since it got cut off

With the code you’ve shared, my hunch is that it’s simply a bug with your use of React’s setState function.

A couple of setState tips:

  1. setState in React is not synchronous, so if you call this.setState({ ... }) to update React state, the state will not be updated yet when you call SavedFractals.insert({ ... }) on the next line. One easy way to fix this is to simply use the callback function that setState lets you pass as a second argument: this.setState({ ... }, mySaveFunction). In this case, mySaveFunction will only be invoked after the state update has completed.

  2. You didn’t ask about this, but it’s considered a best practice not to use this.state to update React state using an object – instead, you should pass an updater function that will receive state and return the state change object.

You can read more about both of those things here:

1 Like

As menewman said, setState is not synchronous. This is so React can batch updates together to improve performance, state will have the updated values during the next render

Hi, ok I tried implementing the system of calling a function after setting the states:

save() {
	this.setState({fractalvalues: [this.state.name, this.state.width, this.state.height, this.state.iterations, this.state.zoom, this.state.panx, this.state.pany, this.state.color]}, this.savetodatabase(this.state.fractalvalues));
}
savetodatabase(data) {
	SavedFractals.insert({
        	fractalvalues: data,
                createdAt: new Date(),
        });	
}

The database saving works but the problem of it saving prior values still persists. I also tried passing the state with a updater function and it worked also but the same problem still occurred.

You should get the fractalValues on the callback, that will ensure the data is already updated in the state.

save() {
	this.setState({fractalvalues: [this.state.name, this.state.width, this.state.height, this.state.iterations, this.state.zoom, this.state.panx, this.state.pany, this.state.color]}, this.savetodatabase);
}
savetodatabase = () => {
        const { fractalvalues } = this.state;
	SavedFractals.insert({
        	fractalvalues,
                createdAt: new Date(),
        });	
};
2 Likes

Ok, thanks! It works perfectly now! :smiley:

As @pmogollon points out, you simply have to wait until the state has finished updating before accessing this.state.

I do want to adjust the suggested code to use the recommended “updater function” pattern – otherwise it’s hypothetically possible you could run into issues with batched state operations:

save() {
  this.setState(state => ({
    fractalvalues: [
      state.name,
      state.width,
      state.height,
      state.iterations,
      state.zoom,
      state.panx,
      state.pany,
      state.color
    ]
  }), this.saveToDatabase);
}