Issue with setState() in if statement - javascript

setState() in if statement:
// morePage = true
// pageNum = 1
if(morePage){
this.setState({pageNum: this.state.pageNum+1})
}
console.log(this.state.pageNum); // return: 1
setState() out if statement:
// morePage = true
// pageNum = 1
if(morePage){
// ...
}
this.setState({pageNum: this.state.pageNum+1})
console.log(this.state.pageNum); // return: 2
I'm facing that right now and I would like to know why...
Thanks :)
EDIT AFTER CORRECT ANSWER:
So yeah I should spend more time reading React's Doc :P
If someone is interested in knowing how I finally did, here is the answer:
In the docs, they say there is no guarantee that your state will have its new value before re-rendering. So you have to use "componentDidUpdate()".
So what I did is, I put the:
this.setState({pageNum: this.state.pageNum+1})
inside a random function I've created, after that in the "componentDidUpdate(prevProps, prevState)" function I can access the new and the old props values, and there I can use the previous and the current value of "pageNum" :)

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.
As mentioned it is not guaranteed that the state value will be updated in your next line of code.
If you want to check the state for debugging try logging it in render method, as this method is invoked after the state is updated

So basically you problem is what others quoted from setState. But you can easily console.log too doing:
this.setState({pageNum: this.state.pageNum+1}, () => {
console.log(this.state.pageNum);
})
See the setState definition:
void setState(
function|object nextState,
[function callback]
)

With setState the current and previous states are merged. Hence the value. Also, its a synchronous so may give unexpected results.

NOTES:
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.
you can get more information from the official documentation
https://facebook.github.io/react/docs/component-api.html

Related

How to change a variable state with react? [duplicate]

I have just found that in react this.setState() function in any component is asynchronous or is called after the completion of the function that it was called in.
Now I searched and found this blog (setState() State Mutation Operation May Be Synchronous In ReactJS)
Here he found that setState is async(called when stack is empty) or sync(called as soon as called) depending on how the change of state was triggered.
Now these two things are hard to digest
In the blog the setState function is called inside a function updateState, but what triggered the updateState function is not something that a called function would know about.
Why would they make setState async as JS is single threaded language and this setState is not a WebAPI or server call so has to be done on JS's thread only. Are they doing this so that Re-Rendering does not stop all the event listeners and stuff, or there is some other design issue.
You can call a function after the state value has updated:
this.setState({foo: 'bar'}, () => {
// Do something here.
});
Also, if you have lots of states to update at once, group them all within the same setState:
Instead of:
this.setState({foo: "one"}, () => {
this.setState({bar: "two"});
});
Just do this:
this.setState({
foo: "one",
bar: "two"
});
1) setState actions are asynchronous and are batched for performance gains. This is explained in the documentation of setState.
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.
2) Why would they make setState async as JS is a single threaded language and this setState is not a WebAPI or server call?
This is because setState alters the state and causes rerendering. This can be an expensive operation and making it synchronous might leave the browser unresponsive.
Thus the setState calls are asynchronous as well as batched for better UI experience and performance.
I know this question is old, but it has been causing a lot of confusion for many reactjs users for a long time, including me.
Recently Dan Abramov (from the react team) just wrote up a great explanation as to why the nature of setState is async:
https://github.com/facebook/react/issues/11527#issuecomment-360199710
setState is meant to be asynchronous, and there are a few really good reasons for that in the linked explanation by Dan Abramov. This doesn't mean it will always be asynchronous - it mainly means that you just can't depend on it being synchronous. ReactJS takes into consideration many variables in the scenario that you're changing the state in, to decide when the state should actually be updated and your component rerendered.
A simple example to demonstrate this, is that if you call setState as a reaction to a user action, then the state will probably be updated immediately (although, again, you can't count on it), so the user won't feel any delay, but if you call setState in reaction to an ajax call response or some other event that isn't triggered by the user, then the state might be updated with a slight delay, since the user won't really feel this delay, and it will improve performance by waiting to batch multiple state updates together and rerender the DOM fewer times.
Good article here https://github.com/vasanthk/react-bits/blob/master/patterns/27.passing-function-to-setState.md
// assuming this.state.count === 0
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
// this.state.count === 1, not 3
Solution
this.setState((prevState, props) => ({
count: prevState.count + props.increment
}));
or pass callback this.setState ({.....},callback)
https://medium.com/javascript-scene/setstate-gate-abc10a9b2d82
https://medium.freecodecamp.org/functional-setstate-is-the-future-of-react-374f30401b6b
You can use the following wrap to make sync call
this.setState((state =>{
return{
something
}
})
Yes, setState() is asynchronous.
From the link: https://reactjs.org/docs/react-component.html#setstate
React does not guarantee that the state changes are applied immediately.
setState() does not always immediately update the component.
Think of setState() as a request rather than an immediate command to update the component.
Because they think
From the link: https://github.com/facebook/react/issues/11527#issuecomment-360199710
... we agree that setState() re-rendering synchronously would be inefficient in many cases
Asynchronous setState() makes life very difficult for those getting started and even experienced unfortunately:
- unexpected rendering issues: delayed rendering or no rendering (based on program logic)
- passing parameters is a big deal
among other issues.
Below example helped:
// call doMyTask1 - here we set state
// then after state is updated...
// call to doMyTask2 to proceed further in program
constructor(props) {
// ..
// This binding is necessary to make `this` work in the callback
this.doMyTask1 = this.doMyTask1.bind(this);
this.doMyTask2 = this.doMyTask2.bind(this);
}
function doMyTask1(myparam1) {
// ..
this.setState(
{
mystate1: 'myvalue1',
mystate2: 'myvalue2'
// ...
},
() => {
this.doMyTask2(myparam1);
}
);
}
function doMyTask2(myparam2) {
// ..
}
Hope that helps.
Imagine incrementing a counter in some component:
class SomeComponent extends Component{
state = {
updatedByDiv: '',
updatedByBtn: '',
counter: 0
}
divCountHandler = () => {
this.setState({
updatedByDiv: 'Div',
counter: this.state.counter + 1
});
console.log('divCountHandler executed');
}
btnCountHandler = () => {
this.setState({
updatedByBtn: 'Button',
counter: this.state.counter + 1
});
console.log('btnCountHandler executed');
}
...
...
render(){
return (
...
// a parent div
<div onClick={this.divCountHandler}>
// a child button
<button onClick={this.btnCountHandler}>Increment Count</button>
</div>
...
)
}
}
There is a count handler attached to both the parent and the child components. This is done purposely so we can execute the setState() twice within the same click event bubbling context, but from within 2 different handlers.
As we would imagine, a single click event on the button would now trigger both these handlers since the event bubbles from target to the outermost container during the bubbling phase.
Therefore the btnCountHandler() executes first, expected to increment the count to 1 and then the divCountHandler() executes, expected to increment the count to 2.
However the count only increments to 1 as you can inspect in React Developer tools.
This proves that react
queues all the setState calls
comes back to this queue after executing the last method in the context(the divCountHandler in this case)
merges all the object mutations happening within multiple setState calls in the same context(all method calls within a single event phase is same context for e.g.) into one single object mutation syntax (merging makes sense because this is why we can update the state properties independently in setState() in the first place)
and passes it into one single setState() to prevent re-rendering due to multiple setState() calls (this is a very primitive description of batching).
Resultant code run by react:
this.setState({
updatedByDiv: 'Div',
updatedByBtn: 'Button',
counter: this.state.counter + 1
})
To stop this behaviour, instead of passing objects as arguments to the setState method, callbacks are passed.
divCountHandler = () => {
this.setState((prevState, props) => {
return {
updatedByDiv: 'Div',
counter: prevState.counter + 1
};
});
console.log('divCountHandler executed');
}
btnCountHandler = () => {
this.setState((prevState, props) => {
return {
updatedByBtn: 'Button',
counter: prevState.counter + 1
};
});
console.log('btnCountHandler executed');
}
After the last method finishes execution and when react returns to process the setState queue, it simply calls the callback for each setState queued, passing in the previous component state.
This way react ensures that the last callback in the queue gets to update the state that all of its previous counterparts have laid hands on.
setState is asynchronous. You can see in this documentation by Reactjs
https://reactjs.org/docs/faq-state.html#why-is-setstate-giving-me-the-wrong-valuejs
https://reactjs.org/docs/faq-state.html#when-is-setstate-asynchronous
React intentionally “waits” until all components call setState() in their event handlers before starting to re-render. This boosts performance by avoiding unnecessary re-renders.
However, you might still be wondering why React doesn’t just update this.state immediately without re-rendering.
The reason is this would break the consistency between props and state, causing issues that are very hard to debug.
You can still perform functions if it is dependent on the change of the state value:
Option 1:
Using callback function with setState
this.setState({
value: newValue
},()=>{
// It is an callback function.
// Here you can access the update value
console.log(this.state.value)
})
Option 2: using componentDidUpdate
This function will be called whenever the state of that particular class changes.
componentDidUpdate(prevProps, prevState){
//Here you can check if value of your desired variable is same or not.
if(this.state.value !== prevState.value){
// this part will execute if your desired variable updates
}
}

Is React's setState() guaranteed to create a new state object every time?

In React, does setState always assign a new object to this.state?
In other words, when you call:
this.setState({
key1: val1,
key2: val2
});
does it always merge the current state object with the new properties into a new object, queueing an operation which is functionally equivalent to the following?
this.state = {
...this.state,
key1: val1,
key2: val2
};
The reason I'm asking is that I'd like to know whether this.state !== nextState is always guaranteed to be true inside shouldComponentUpdate() if the update was triggered by setState.
Thanks.
The simple answer to your question will be "Yes", but for one update cycle. Let me explain this.
As you may already know React setState does not always immediately update the component. Sometimes React batch or defer the updates until later. As an example, let's assume you have something like follows in your event handler.
onClick() {
this.setState({quantity: state.quantity + 1});
this.setState({quantity: state.quantity + 1});
this.setState({quantity: state.quantity + 1});
}
These state update will be queued and execute all together in one update cycle. In such scenario React only create a new state object for the first setState and that object will mutate for subsequent setState updates. You can clearly see this in the source code here.
However, this is something totally about how React works under the hood and we won't need to worry about that. Because there will be only one shouldComponentUpdate() and componentDidUpdate() for one cycle. By the time we access the state it will be always a new object. So we can safely assume that setState() guaranteed to create a new state object every time. But make sure that you aware of other implications of setState which explains in the official documentation.
I'd like to know whether this.state !== nextState is always guaranteed
to be true inside shouldComponentUpdate().
The answer to your this question will be "No" as also explained in other answers. shouldComponentUpdate() will be called because of either state change, props change or both. So this.state !== nextState won't true if the component has updated only because of props change.
I think you want to know the answer to this question.
Will this.state !== nextState is always guaranteed to be true inside
shouldComponentUpdate() ?
According to react docs shouldComponentUpdate will be called on three instance
state changed
props changed
state and props changed
So if only props are changing, your current state will be equal the last unmodified state.
shouldComponentUpdate() is invoked before rendering when new props or state are being received. Defaults to true. This method is not called for the initial render or when forceUpdate() is used.
The first question that you asked are depends on your style of data management for your state.
React lets you use whatever style of data management you want, including mutation.
And the docs also states that
shallow merge of stateChange into the new state, e.g., to adjust a shopping cart item quantity
But looking at the internal parts of setState beginUpdateQueue method let me doubtful when state gets mutated.
I think it would be wise to use immutability-helper for this part of the code, if you must guarantee that no mutation happens to the data.

React keep to single setState call?

Supposed that in a function, i always need to set someState, and only need to set someOtherState if condition is true.
Is it preferable to do it like this:
this.setState({ someState });
if (condition) {
this.setState({ someOtherState });
}
Or this?
if (condition) {
this.setState({ someState, someOtherState });
} else {
this.setState({ someState });
}
I know React is optimized such that calling setState in quick succession will usually not result in a re-render. But is that behavior guaranteed or should the code make such assumption?
eg. supposed it works by re-rendering on a fixed time interval, if the first setState get called right before that interval block ends, then the second setState will result in a re-render?
Why don't you use ternary operator? If condition is true, set it to new state. Otherwise, use the old one.
this.setState(prevState => ({
someState,
someOtherState: condition ? newSomeOtherState : prevState.someOtherState
}))
React batches setState calls, so doing sequential update calls should only trigger one call to render.
You can assume that it will be batched provided you are within React managed event functions (React event system). For example, if it's an AJAX call, or some other delayed function like a promise or setTimeout, they will not be batched.
EDIT
This post has a pretty good summary of the order of events in most situations. You will find the state section about halfway down, but I'll try to summarise here:
Order goes :
Updating State
ShouldComponentUpdate

ComponentWillUpdate
Render
...
If you're calling multiple functions within one of these, React is smart enough to wait until they're complete before running the batched updates.
See the React docs here for details on setState:
(Link limit: facebook.github.io)/react/docs/react-component.html#setstate
and also a discussion on batching here:
https://groups.google.com/forum/#!topic/reactjs/G6pljvpTGX0

How does react update state?

I'm getting a very strange issue that I don't know how to address.
I've got a fairly straightforward method: When a button is pressed it called toggleInverted()
toggleInverted() {
if(this.state.inverted){
this.setState({inverted: false});
} else{
console.log("got to else...");
this.setState({inverted: true});
console.log(this.state.inverted);
}
}
The inverted field is initialized in the constructor to false. However the first time I click the button when I load the page, it doesn't correctly reset the state. The output is:
got to else...
false.
So somehow it is getting into this else statement, executing the setState, and yet not setting inverted to be true...
Is there something about setState that I am missing?
setState does not change your components state immediately. Your state change may be asynchronous and thus no guarantee that your console.log statement will print the changed state. setState however does always lead to the render method being called, so if you console log your state inside the render method of your component, your state should be true.
Also, this.setState({inverted: !this.state.inverted}) is a shorter version of your code snippit
setState may be asynchronous
Meaning you cannot expect the values of this.state to change immediately after setState is called.
To quote the docs:
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...
As an aside, you can figure your code by using the negative expression of the current inverted value as follows:
toggleInverted() {
this.setState({inverted: !this.state.inverted});
}

How do I update the state (using ReactJS) if I should not call setState in componentWillUpdate?

When I setState in componentWillUpdate, componentWillUpdate runs in an infinite loop that doesn't stop getting triggered.
This never gives my render a chance to reflect my changes. How can I change the state if I shouldn't use componentWillUpdate?
Edit: I already have some understanding that setState should not be called in componentWillUpdate. I'm just confused what I should do as an alternative.
Edit #2: I started with componentWillReceiveProps but I can't seem to trigger this function when my Parent component changes state. I provide that state from the parent as a props to my child.
First thing to do is to check official documentation for this method (link). Where you can read when the function is actually called.
Then read common mistake(note):
You cannot use this.setState() in this method. If you need to update state in response to a prop change, use componentWillReceiveProps instead.
You change the state and React automatically calls componentWillUpdate.
I understand this is cautioned against in the guide but I am not sure I can see the problem with calling setState from within componentWillUpdate. True, it may result in infinite recursion unless of course you provide a bottom to that recursion (a way to break out of it). E.g. a way could be to check the second (nextState) parameter in componentWillUpdate and not invoke setState again if some condition is met (which is when the recursion ends).
As a minimal example, imagine a component that has no properties at all, only two pieces of state. Further imagine that the second piece of state is asynchronously obtained from the first. E.g. the first piece of state could be some parameter to provide to an Ajax call, and the second piece of state is the result of that call. So basically you call this.setState to configure the parameters and then inside componentWillUpdate you can do something like the following (to keep things simple I use a window.setTimeout as a placeholder for an Ajax call):
const ComponentWithAsyncState = React.createClass({
getInitialState: function() {
return {
ajaxParams: '',
ajaxResult: ''
};
},
setAjaxParams: function(params) {
this.setState({ajaxParams: params});
},
componentWillUpdate: function(_, nextState) {
if (nextState.ajaxParams!=this.state.ajaxParams)
window.setTimeout(function imagineThisIsAjax() {
this.setState({ajaxResult: `result from ${nextState.ajaxParams}`});
}.bind(this), 2000);
},
When, (e.g. through some controls managed by this component) the ajaxParams change, the sequence of actions will be something like (where ~~> denotes asynchronicity):
setAjaxParams --> this.setState --> componentWillUpdate ~~> imagineThisIsAjax --> this.setState --> componentWillUpdate
I.e. the second call to componentWillUpdate will not result in a further this.setState and thus the recursion will end there.

Categories

Resources