Avoiding `setTimeout` 'hack' to ensure state is in sync - javascript

I wrote a small todo app using React, in which the user can add and remove items to their list.
As a bonus feature, the list is saved to localStorage as it's mutated by the user, and used on the initial mount of the component.
In both the addTodo and removeTodo methods, the pattern is this:
Set the new state by adding or removing an item of this.state.todos
Copy the state to localStorage
For example, here is the removeTodo method:
removeTodo(indexOfItemToRemove) {
const todosCopy = this.state.todos.slice();
todosCopy.splice(indexOfItemToRemove, 1);
this.setState({
todos: todosCopy
});
this.updateLocalStorageWithState();
}
Here is what I am currently doing to save this.state.todos to localStorage
updateLocalStorageWithState() {
setTimeout(() => {
localStorage.setItem('localStorageTodos', JSON.stringify(this.state.todos));
}, 1);
}
I found that without using setTimeout, the localStorage was always 1 step behind, using what the user might perceive as an outdated version of the list.
This feels like a hack. How can I incorporate a way of doing the same thing without having to use a setTimeout hack?

setState() is not necessarily executed synchronuosly. This causes the behavior you are experiencing:
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.
Source
Luckily, setState() takes a second parameter, which is a callback that is called when the state update has been completed. You can use that to synchronize your local storage entry:
this.setState({
todos: todosCopy
}, () => {
localStorage.setItem('localStorageTodos', JSON.stringify(this.state.todos));
});
Alternatively, why not set the local storage entry directly instead of reading from state first?
this.setState({
todos: todosCopy
});
localStorage.setItem('localStorageTodos', JSON.stringify(todosCopy));

Related

unable to set value using useState Hook in reactjs [duplicate]

I'm reading Forms section of reactjs documentation and just tried this code to demonstrate onChange usage (JSBIN).
var React= require('react');
var ControlledForm= React.createClass({
getInitialState: function() {
return {
value: "initial value"
};
},
handleChange: function(event) {
console.log(this.state.value);
this.setState({value: event.target.value});
console.log(this.state.value);
},
render: function() {
return (
<input type="text" value={this.state.value} onChange={this.handleChange}/>
);
}
});
React.render(
<ControlledForm/>,
document.getElementById('mount')
);
When I update the <input/> value in the browser, the second console.log inside the handleChange callback prints the same value as the first console.log, Why I can't see the result of this.setState({value: event.target.value}) in the scope of handleChange callback?
From React's documentation:
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.
If you want a function to be executed after the state change occurs, pass it in as a callback.
this.setState({value: event.target.value}, function () {
console.log(this.state.value);
});
As mentioned in the React documentation, there is no guarantee of setState being fired synchronously, so your console.log may return the state prior to it updating.
Michael Parker mentions passing a callback within the setState. Another way to handle the logic after state change is via the componentDidUpdate lifecycle method, which is the method recommended in React docs.
Generally we recommend using componentDidUpdate() for such logic instead.
This is particularly useful when there may be successive setStates fired, and you would like to fire the same function after every state change. Rather than adding a callback to each setState, you could place the function inside of the componentDidUpdate, with specific logic inside if necessary.
// example
componentDidUpdate(prevProps, prevState) {
if (this.state.value > prevState.value) {
this.foo();
}
}
You could try using ES7 async/await. For instance using your example:
handleChange: async function(event) {
console.log(this.state.value);
await this.setState({value: event.target.value});
console.log(this.state.value);
}
Watch out the react lifecycle methods!
http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/
https://reactjs.org/docs/react-component.html
I worked for several hours to find out that getDerivedStateFromProps will be called after every setState().
😂
Sometime this issue occurs with state.
In case of hooks, you should use useEffect hook, As below-
const [fruit, setFruit] = useState('');
setFruit('Apple');
useEffect(() => {
console.log('Fruit', fruit);
}, [fruit])
This saved my day, Hope will help you!!!
Accessing this.state after calling the setState method is not guaranteed to return the updated status due to the asynchronous nature of setState.
To guarantee an update after calling setState, there are two solutions you may pursue.
Solution 1: As mentioned in one of the above answers, put your code in the componentDidUpdate method
Solution 2: As mentioned in another of the above answers, pass your stuff as a callback
this.setState({value: myValue}, function () {
this.functionThatIsExecutedWhenStateIsUpdated();
});
It's important to note that these two solutions are not clearly interchangeable. The one cannot easily solve all the use-cases of the other. As a general rule, if you can, best practice says that solution 1 is preferred. But, there are use-cases where only solution 2 "more effectively" works such as the "update-my-view-and-post-my-data" use case. This use case goes like this:
After adding an item, say, "Add Schedule", I want to both add that item to a front-end list and immediately post the just-updated-list to the backend, as demonstrated in the concept below:
If you dont do either solution, i.e. if you only say this in your code:
addToItemArray = () => {
this.setState{{ scheduledItemsArray: newObjectListWithMax}}
this.postData();
}
<button className="btn btn-secondary btn-block" onClick={this.addToItemArray}>Add Shedule</button>
... you will post the list excluding the "Delivery to Max" item, because the state wont be updated when you this.postData() (again, because its asynchronous).
If you utilise solution 1, you would make a POST after typing in every character in the Schedule Name textbox!
There are other ways aswell to cater for this use-case but solution 2 best conveys the intent when reading the code.
Given the ubiquitous nature of this use case in virtually every web app, the callback technique explained by Michael's answer is an indispensable piece of code in every developers toolkit.
async-await syntax works perfectly for something like the following...
changeStateFunction = () => {
// Some Worker..
this.setState((prevState) => ({
year: funcHandleYear(),
month: funcHandleMonth()
}));
goNextMonth = async () => {
await this.changeStateFunction();
const history = createBrowserHistory();
history.push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}
goPrevMonth = async () => {
await this.changeStateFunction();
const history = createBrowserHistory();
history.push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}
React bathces different set state calls so that it can determine what is the most optimal strategy for rerendering the website is going to be.
Imagine you have an application where you have a lot of different components. Perhaps, with one button click you are updating the state in multiple components, not just on the current one. In this case, React does not want to just completely isolate and do all those different updates independently.
React wants to figure out if it can stack all these updates together, maybe there is a more optimal way of updating these components so that it is more performant. This is what React is doing behind the scenes. As a result, set state call is asynchronous call.
Simply putting - this.setState({data: value}) is asynchronous in
nature that means it moves out of the Call Stack and only comes back
to the Call Stack unless it is resolved.
Please read about Event Loop to have a clear picture about Asynchronous nature in JS and why it takes time to update -
https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4
Hence -
this.setState({data:value});
console.log(this.state.data); // will give undefined or unupdated value
as it takes time to update.
To achieve the above process -
this.setState({data:value},function () {
console.log(this.state.data);
});

React controlled input [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
}
}

In React after calling setState, are there hard and fast rules for avoiding asynch errors when accessing/changing state?

I am learning React and this is my first time handling asynchronous operations. Currently I am building a simple calculator and have run into some minor issues after using setState and then immediately trying to access the state. It's been easy to work around the issues because my app is pretty simple. However, I haven't been able to find definitive rules for how long it takes after calling setState to be certain that state has actually been updated. Does it require a certain amount of time? Is it dependent on the structure of my code? Also, is it appropriate to use setTimeout after setState in order to give state time to update? If anyone could give me some insight into when React will update the state and save me the guesswork, it would be appreciated.
Does it require a certain amount of time?
No specific amount.
Is it dependent on the structure of my code?
In a general way, but that's not really the question. :-)
Also, is it appropriate to use setTimeout after setState in order to give state time to update?
No.
In React after calling setState, are there hard and fast rules for avoiding asynch errors when accessing/changing state?
Yes. They're covered in the documentation, particularly here. They are (at minimum):
The only way to know state has finished changing is to use componentDidUpdate or the completion callback you can provide to setState (the second argument):
this.setState(newState, () => {
// `this.state` has the updated state
});
If you're changing state based on existing state, you must use the form of setState that accepts a function as its first argument and calls it with the up-to-date state for you to change.
(Not async specific.) Never directly modify the state object or any object it refers to.
So for example: Suppose you have an array (items) and you need to push an entry into it if it's not already there:
// WRONG, breaks Rule #3
if (!this.state.items.includes(newItem)) {
this.state.items.push(newItem);
}
// WRONG, breaks Rule #2
if (!this.state.items.includes(newItem)) {
this.setState({items: [...items, newItem]});
}
// WRONG, breaks Rule #1
this.setState({items: [...items, newItem]});
doSomethingWith(this.state.items);
Instead:
this.setState(
({items}) => {
if (!items.includes(newItem)) {
return {items: [...items, newItem]};
}
},
() => {
doSomnethingWith(this.state.items);
}
);
But note that using the completion callback (the second function above) is usually an anti-pattern; really the only thing a component should do when state updates is re-render, and React will call render for you.
But this answer is not a substitute for reading through the documentation. :-)
setState takes a callback as second parameter:
this.setState({
foo: 'bar'
}, () => {
// This code will be executed after setState has been processed
});
Ideally, your components don't care about the timing of a setState update.
Most likely what you are looking for is the setState call that is based on the previous state...
this.setState((prevState) => {
return {
// I almost always just spread the state onto a new object.
...prevState,
// Then you'll want to add your updated properties below. This overrides the old state that you set above
someProp: newVal
};
});
From there, again, your components shouldn't care about when React actually performs the update! (As with all things there are exceptions of course)
If you want to access the state after setState() you can do that in the callback function for the same to verify the actual state is being updated.
Like this:
this.setSate ({
test : 'Hello Word'
}, () => {
console.log('this.state', this.state)
})
Whenever the state is changed, it compares the DOM and virtual DOM to find out differences, and renders them on the actual DOM.
https://reactjs.org/docs/state-and-lifecycle.html

ReactJS - setState does not update property [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
}
}

Why is setState in reactjs Async instead of Sync?

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
}
}

Categories