ForceUpdate () vs this.setState () with callback

The reason for this is the use of state variables that have their own functions. There are two ways that I can think of. One of them is to mutate this.state directly (well, like, I know that this is discouraged) by calling state functions, then call forceUpdate() and figure out what it brings. Another way is to execute a callback function. What is the right way?

Here is an example of what I'm talking about. I work with Vis.js , and their DataSet object allows you to add data to an existing dataset - 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)); } 
+4
source share
2 answers

You definitely should not mutate this.state , or anything in it, ever. From Process Component API Documents :

NEVER mutate this.state directly, since calling setState () can subsequently replace the mutation you made. Treat this.state as immutable.

setState () does not immediately mutate this.state, but creates a pending state transition. Access to this.state after calling this method can potentially return an existing value.

There is no guarantee that setState calls will work synchronously, and calls can be collected to improve performance.

setState () always causes re-rendering if conditional playback logic is not implemented in shouldComponentUpdate (). If mutable objects are used and the logic cannot be implemented in shouldComponentUpdate (), calling setState () only when the new state is different from the previous state will avoid unnecessary re-rendering.

Even your second example is incorrect here, as you are still mutating this.state . The second parameter is just a callback when the state has been updated. What you want to do is somehow get the new objects and pass them to setState . Not very familiar with Vis.js, this seems rather complicated since it has no operations that return completely new / immutable datasets. There are not even copy or clone operations. It looks like you will need to create a completely new vis.DataSet each time and add data from the original, then add new data, then this.setState( { graphData: newGraphData, ... } )

Ultimately, this is likely to be a “clean” and proper way to do this.

All that is said, and with a big YMMV warning - since there is no obvious way to treat vis.DataSet as immutable, you can probably just go with the first option.

Take the first part of the warning in the docs:

calling setState () can subsequently replace the mutation you made

What will happen in this case? Nothing, since the actual object in your state is changed, this is only one link forever. If React “replaces it,” it will simply replace it with itself. In other words, until you never call setState with a completely new DataSet, it will not be replaced with the unexpected at the unexpected time.

The big problem here will be that calling forceUpdate will force re-rendering, and this can be slow. But basically it sounds like you want it to re-display no matter what, anyway, when this function is called, so ... pragmatically speaking, you're probably good :)

+4
source

To mutate the state of a component, we should always use this.setState () , because it tells React that something has changed in the state of the component, and then React will take care of re-rendering in its own way. However, we can also mutate the state object using this.state.yourProperty = somethingNew , but we should never do this because it is shown too much and React is not aware of our state mutations, so we must explicitly trigger re-rendering by calling this.forceUpdate () . A good example of using this.forceUpdate is integration with another library such as D3.js. D3 has its own datasets, so suppose that if something changes in the D3 dataset, then it needs to say React: “Hey! React I am changing some of my things, and now I just need to redraw ', so D3 will cause the opposite call using this.forceUpate () .

0
source

All Articles