forceUpdate() vs. this.setState() with a callback

reactjs

Solution

You definitely should not mutate `this.state`, or anything in it, ever. From the React Component API docs:

NEVER mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.

setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.

There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.

setState() will always trigger a re-render unless conditional rendering logic is implemented in shouldComponentUpdate(). If mutable objects are being used and the logic cannot be implemented in shouldComponentUpdate(), calling setState() only when the new state differs from the previous state will avoid unnecessary re-renders.

Even your second example isn't correct here, since you're still mutating `this.state`. The second parameter is merely a callback for when the state has been updated. What you want to do is somehow get new objects and give those to `setState`. Not being very familiar with Vis.js, this seems to be kind of tricky since it doesn't seem to have any operations that return entirely new/immutable data sets. There aren't even copy or clone operations. It looks like you'd have to actually make an entirely new `vis.DataSet` each time and add the data from the original, then add the new data, then `this.setState( { graphData: newGraphData, ... } )`

Ultimately that will probably be the 'pure' and correct way to do this.

All that said, and with a big YMMV caveat - since there's no apparent way to treat `vis.DataSet`s as immutable, you can probably just go with the first option.

Take that first part of the warning in the docs:

calling setState() afterwards may replace the mutation you made

What will happen in that case? Nothing, since the actual object in your state is mutable, it's just the one reference forever. If React 'replaces it' it will just be replacing it with itself. In other words, as long as you never call setState with an entirely new DataSet, it won't get replaced with something unexpected at an unexpected time.

The big problem here will be that calling `forceUpdate` will, well, force a re-render, and that could be slow. But it mostly sounds like you want it to re-render no matter what anyway when that function is called, so... pragmatically speaking you're probably ok :)

Problem

The reason for this is when dealing with `state` variables that have their own functionality. There are two ways I can think of. One is to mutate `this.state` directly (well, sort of, I know it's discouraged) by calling the state functions, then call `forceUpdate()` and deal with what that brings. The other is to do the callback function. Which is the proper way? Here's an example of what I am talking about. I'm working with Vis.js, and their DataSet object allows you to add data to an existing data set - nodes and edges, for example. ``` addDataToGraph: function(data) { // Is this the proper way to do something like this? this.state.graphData.nodes.add(nodes); this.state.graphData.edges.add(edges); this.forceUpdate(); // Or is this the right way - the question I am posing here this.setState({ currentChunk: data.currentChunk, totalChunks: data.totalChunks }, function() { this.state.graphData.nodes.add(data.nodes); this.state.graphData.edges.add(data.edges); }.bind(this)); } ```

Original source