Haze about 'setState' in React official doc - reactjs

I am reading react.js official docs.
Here is one of them.
I am confused about this paragraph:
setState() will always lead to a re-render unless
shouldComponentUpdate() returns false. If mutable objects are being
used and conditional rendering logic cannot be implemented in
shouldComponentUpdate(), calling setState() only when the new state
differs from the previous state will avoid unnecessary re-renders.
Question: Why calling setState() will avoid unnecessary re-renders if mutable objects are being used and conditional rendering logic cannot be implemented in shouldComponentUpdate()?

shouldComponentUpdate deep-dive might help you
Calling setState() will always trigger a re-render of the component(unless you have defined shouldComponentUpdate()). But keeping performance and efficiency in mind, we want the component to re-render only if the state value has actually changed.
This is where shouldComponentUpdate() lifecycle method comes into play.
In this method, a check can be done to determine whether the state value has changed. If state has changed, returns true and the component re-renders.
Mutable objects refer to Arrays, objects etc in javascript. Numbers and Strings are immutable.
Mutable object example:
const a = [1,2]; // memory address of a is 0xff456e
a.push(3); // memory address of a is 0xff456e(same)
Immutable object example:
let b = 'Hello'; // memory address of b is 0xee789e
b = 'World'; // memory address of b is 0xee789f(different because its a new object created with value 'World')
If your component is a PureComponent, then react by default will define the shouldComponentUpdate() to reduce unnecessary re-renders. But you need to use immutable objects for that to work correctly(i.e create a new array or object manually and assign to your state, else your component won't re-render correctly).
So, the point they are making is this : Don't call setState() unless the state value has actually changed if your using a normal react component without a shouldComponentUpdate() check to avoid situations like this:
this.setState({ items: [1, 2, 3] }); // re-render once
// lot of code goes here
this.setState({ items: [1, 2, 3] }); // re-render twice
Note: Although the value of items is unchanged, there is a wasteful re-render of the component caused as shown above. So, avoid setting state if there is no change of value.

I think you read that wrong.
It's a two term conditional:
IF
mutable objects are being used
AND
conditional rendering logic cannot be implemented in shouldComponentUpdate()
THEN
[you should call] setState() only when the new state differs from the previous state [so it] will avoid unnecessary re-renders.
(Alteration by me are in brackets.)
Basically, it means that it's up to you to test if you should call setState if you can't rely on React's internal tests due to technical limitations on your side.

The doc wanted to say that in the following conditions, the re-render will not happen:
If shouldComponentUpdate hook returns false.
If mutable objects are being used.
If some conditional logic is not used for re-render like force update inside shouldComponentUpdate hook.
If the effect of calling setState method only change the previous state value.
BTW, I'm still not satisfied that I couldn't make clear enough. :(:

Related

ReactJS, Calling setState with same parameter

I have been reading the React docs and came across shouldComponentUpdate(). My understanding is that everytime setState() is called, a re-render of that component will be updated.
My question is that If the value to be updated is the SAME as the current state value, would this trigger a re-render event? or I would have to manually checks for the current value and value to be updated in shouldComponentUpdate()
The official React documentation states:
The default behavior is to re-render on every state change...
https://reactjs.org/docs/react-component.html#shouldcomponentupdate
This means that by default, render() will be executed if any of a component's state or props values changes.
You can override this default behavior using shouldComponentUpdate(). Here's an example that only updates if a state value changes.
shouldComponentUpdate(nextProps, nextState) {
return this.state.someValue !== nextState.someValue;
}
Note: this example completely ignores props. So, any changes to props will not trigger render().
Adding more to #Jyothi's answer regarding implementing shouldComponentUpdate() to skip unnecessary re-renders, in React 15.3 they introduced a new concept PureComponent. From reactjs docs
The difference between them is that React.Component doesn’t implement
shouldComponentUpdate(), but React.PureComponent implements it with a
shallow prop and state comparison.
This allows to skip unnecessary calls of render in class components by just implementing PureComponent instead of the usual Component. There are a few caveats with PureComponent though, from the docs about React.PureComponent’s shouldComponentUpdate():
... only shallowly compares
the objects. If these contain complex data structures, it may produce
false-negatives for deeper differences.
... skips prop updates for the whole component subtree. Make sure all the
children components are also “pure”.
Usage of PureComponent can in some cases improve performance of your app. Moreover, it enforces you to keep state and props objects as simple as possible or even better, immutable, which might help simplify the app structure and make it cleaner.
I dont know if I understood your question correctly but react only re renders when there is difference between virtual dom and real dom.
And as Jyothi mentioned in his answer that render method will be called irrespective of the value passed in the set state function but rerendering will depend on what this render method returns.
In functional components, calling setState() with the equal value won't cause a rendering, while in a class component it does: https://dev.to/sunflower/reactjs-if-it-is-setting-a-state-with-the-same-value-will-the-component-be-re-rendered-5g24
Note that we're just talking about virtual (React) renderings here. Brower-rendering won't happen in any case - i.e. neither in the functional component nor in the class component - as long as the state (or to be more precise: the effective DOM) doesn't change.

How to ignore a property update of the state in ReactJs?

I know that you can use shouldComponentUpdate to decide if render should be called or not. Citing the docs :
By default, shouldComponentUpdate always returns true to prevent
subtle bugs when state is mutated in place, but if you are careful to
always treat state as immutable and to read only from props and state
in render() then you can override shouldComponentUpdate with an
implementation that compares the old props and state to their
replacements.
But my trouble is a bit different. I calculate a value in componentDidUpdate because a need a first render to be able to do my computation, and i'd like to store this value on the state to be able to use it later on in the render function, but I dont want to trigger a render when I modify it.
How would you do it ? Is this the proper way to go ?
Should I store this value somewhere else ? Directly on the this ?
Compute your state before component is actually updated.
componentWillUpdate(nextProps, nextState) {
nextState.value = nextProps.a + nextProps.b;
}
Your component will get computed value with other changes and will update only one time.

Setting state by assignment

In react, is there a reason why someone would want to set the state of a variable by assignment instead of calling setState(...)
Example:
// accessing state var directly
this.state.myVar = 'changed state'
// instead of calling setState
this.setState({myVar: 'changed state'})
To me this seems like an anti-pattern. But maybe there's a good explanation why sometimes it's necessary?
It's necessary, because React has to know wether this.state is considered mutated. There is no dirty-checking in React. The state object is considered dirty when this.setState is called, and no further comparisons are made to its previous state. This answer might help explain this in more detail: Why is React's concept of Virtual DOM said to be more performant than dirty model checking?
Setting (mutating) the state directly will work in this case:
this.state.myVar = 'changed state'
However, it should be avoided according to the React docs:
NEVER mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.
The main problem with mutating the state is that it prevents some of the React lifecycle methods from working. For example, React's shouldComponentUpdate() method is often used to speed up the app when dealing with a large number of components. The method allows you to skip re-rendering a component if the state has been updated:
// Return false if you want to skip the `render()` method
shouldComponentUpdate: function(nextProps, nextState) {
return this.state.myVar === nextState.myVar;
}
The above will not work if you are mutating the state. this.state.myVar and nextState.myVar references are the same and therefore the above will always return true.

ReactJS: Why shouldn't I mutate nested state?

I've read the ReactJS documentation about setState. Specifically, this line:
NEVER mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.
But in my code, I do things like this:
var x = this.state.x;
x.y.z.push("foo"); // z is a list
this.setState({x:x});
This code seems to work and update state correctly. But according to the documentation, I'm breaking the rules. What's the problem with this approach? Are there performance issues? Race conditions? Will I be scolded by the Facebook dev team? Ideally, I'd like to avoid the immutability helpers and all the other craziness and keep things simple.
By manipulating state directly, you are circumventing React's state management, which really works against the React paradigm. The most significant benefit of React's setState is that it immediately triggers a re-render, which merges your DOM changes from the shadow DOM into the document DOM. So, you capture all the state changes you need in some handler, then build up the state changes you want in a literal object, then pass that to setState. This is not quite what your example above does.
So while the code sample you provided technically breaks this rule, since you are calling setState directly after mutating through a reference to a state object property, your changes are immediately being funneled through React's state management. So, everything will work as you expect. The idea is that you don't want to get in the habit of making many changes to state in this way, it's better to capture your intended state in a new literal object or array, then set it to the state once (i.e., with no previous mutations of state) through a call to setState, which will trigger a single re-render.
EDIT: To more definitively answer your question, I would add that the real concern is that a dev would directly manipulate state in many different places or methods, without calling setState, and then at some later point or other code, call setState and then wonder why their render isn't producing the results they expected. Since setState does an object merge between the known, managed state, and the literal object passed as an argument to setState, it's possible the results would not be what you would expect if you had previously manipulated state directly.
The reason is that you miss out on the callbacks associated with this.setState and they claim that you may overwrite data by just assigning straight to the object.
Also, often in OOP (I don't know how many stars JS gets...) you'll use getter and setter methods instead of directly manipulating the object. In this example via this.state.prop1 = "xyz";
I've never had react overwrite my directly set state properties. The temptation to code it this way may be write to state without re-rendering. But if you're doing that you may think about not putting those in state anyways.
If re-rendering performance is an issues checkout https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate
The main reason is that shouldComponentUpdate will not work correctly.

What is the correct way of setting state variables in Reactjs and what is the difference between these approaches?

I was working with React JS and I was wondering the difference between calling setState() twice to set two different state variables like this:
this.setState({fruit1: “apple”});
this.setState({fruit2: “mango”});
AND
calling setState() once and passing both state variables as JSON like this:
this.setState({fruit1: “apple”, fruit2: “mango”});
Also what is the better practice: putting state variable names in double quotes like this: this.setState({"fruit1": “apple”}) or simply ignoring the quotes?
From React documentation:
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.
So, use this.setState({fruit1: “apple”, fruit2: “mango”});
For the second question you can look here and here
Inside a React event handler (that is, a function called from a React-based onChange={...} property and the like), multiple calls to setState are batched and the component is only re-rendered a single time. So, there's no difference between
handleClick: function() {
this.setState({fruit1: "apple"});
this.setState({fruit2: "mango"});
}
and
handleClick: function() {
this.setState({fruit1: "apple", fruit2: "mango"});
}
However, outside of the React event system, the two calls to setState will not be merged unless you wrap them in a function passed to React.addons.batchedUpdates. This is normally not something you have to worry about, but may become an issue if you start setting state in response to asynchronous events (e.g. timers, promises, callbacks, etc). For that reason, I would generally recommend the second form (with the two objects merged into one) over the first.
Here is a detailed explanation of React States and setState() method.
States (and props) are only two reasons why React re-renders/recalculate the DOM. It means if we change State, we are telling react to change the related behaviour of our app.
State is a Java-Script object with key:value pair. Now we may have many States (many key:value pairs) and let's say at certain point only one state is changing. in that case we may use this.setState() method to change only that specific state.
state = { fruit1: 'mango', fruit2: 'apple' }
let's say we want to update fruit1: 'watermelon'.
Here we can say:
this.setState( {fruit1: 'watermelon'} );
Here, we did not say anything about second state (fruit2), so react will merge changed state (fruit1) with old state (fruit2).
While, we can also say:
this.setState( {fruit1: 'watermelon' ,fruit2:'apple'} );
But it is not necessary.
Correct and Re-commanded way of setting/changing State:
From React Official docs:
Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.
So here is a better way to do it:
If we are updating the counter or calculating something:
this.setState((prevState,props) => {
return {
{ counter: prevState.counter+1; }
}

Resources