Is there a synchronous alternative of setState() in Reactjs
As you have read from the documentation, there is NO sync alternative, reason as described is performance gains.
However I presume you want to perform an action after you have changed your state, you can achieve this via:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
x: 1
};
console.log('initial state', this.state);
}
updateState = () => {
console.log('changing state');
this.setState({
x: 2
},() => { console.log('new state', this.state); })
}
render() {
return (
<div>
<button onClick={this.updateState}>Change state</button>
</div>
);
}
}
ReactDOM.render(
<MyComponent />,
document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
In ReactJS, why does `setState` behave differently when called synchronously?
Here's what's happening.
Synchronous
- you press X
- input.value is 'HelXlo'
- you call
setState({value: 'HelXlo'})
- the virtual dom says the input value should be 'HelXlo'
- input.value is 'HelXlo'
- no action taken
Asynchronous
- you press X
- input.value is 'HelXlo'
- you do nothing
- the virtual DOM says the input value should be 'Hello'
- react makes input.value 'Hello'.
Later on...
- you
setState({value: 'HelXlo'})
- the virtual DOM says the input value should be 'HelXlo'
- react makes input.value 'HelXlo'
- the browser jumps the cursor to the end (it's a side effect of setting .value)
Magic?
Yes, there's a bit of magic here. React calls render synchronously after your event handler. This is necessary to avoid flickers.
can't setState in reactjs
That is because setState()
is asynchronous. According to the React documentation for state,
setState() does not always immediately update the component. It may
batch or defer the update until later.
Furthermore,
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.
If you wish to read more about why state isn't updated immediately, feel free to read this, it is pretty in depth when it comes to explaining it.
How can I 'await' setState update or something to the same effect?
React state updates are asynchronously processed, but the useState
state updater function is completely synchronous and doesn't return a Promise, so it can't be awaited.
You can collect your errors in the handler and issue a single state update.
function handleClick(event) {
console.log(values);
const errors = {};
// make sure email is not empty
if (values.email.length === 0) {
errors.email = [{msg: "Email can not be empty."}];
}
// make sure password is not empty
if (!values.password.length) {
errors.password = [{msg: "Password can not be empty."}];
};
console.log('about to submit: ', errors);
if (Object.keys(errors).length) { // if there are errors
setErrors(errors);
return;
}
console.log('data is clean');
}
Why does Async Await work with React setState?
I tried to do my best to simplify and complement Davin's answer, so you can get a better idea of what is actually going on here:
- await is placed in front of this.handleChange, this will schedule the execution of the rest of changeAndValidate function to only run when await resolves the value specified to the right of it, in this case the value returned by this.handleChange
this.handleChange, on the right of await, executes:
2.1. setState runs its updater but because setState does not guarantee to update immediately it potentially schedules the update to happen at a later time (it doesn't matter if it's immediate or at a later point in time, all that matters is that it's scheduled)
2.2. console.log('synchronous code') runs...
2.3. this.handleChange then exits returning undefined (returns undefined because functions return undefined unless explicitly specified otherwise)
await then takes this undefined and since it's not a promise it converts it into a resolved promise, using Promise.resolve(undefined) and waits for it - it's not immediately available because behind the scenes it gets passed to its .then method which is asynchronous:
“Callbacks passed into a promise will never be called before the
completion of the current run of the JavaScript event loop”
3.1. this means that undefined will get placed into the back of the event queue, (which means it’s now behind our setState updater in the event queue…)
event loop finally reaches and picks up our setState update, which now executes...
event loop reaches and picks up undefined, which evaluates to undefined (we could store this if we wanted, hence the = commonly used in front of await to store the resolved result)
5.1. Promise.resolve() is now finished, which means await is no longer in affect, so the rest of the function can resume
- your validation code runs
setState didn't update the set value in React
In React setState
is asynchronous, which means that the sate value won't be modified right after you call setState
and that is why you get the old values from the console.log.
Why is setState in reactjs Async instead of Sync?
React Docs
handleFilter = (event) => {
console.log(this.state.answerStatus) // Before update 'all'
let val= event.target.value === "answered";
console.log(val); // true or false
this.setState({answerStatus:val}, () => {
console.log(this.state.answerStatus);
});
}
Related Topics
Firebase Query If Child of Child Contains a Value
Validate Decimal Numbers in JavaScript - Isnumeric()
How to Create and Read a Value from Cookie With JavaScript
Settimeout in For-Loop Does Not Print Consecutive Values
When Should I Use Arrow Functions in Ecmascript 6
Negative Lookbehind Equivalent in JavaScript
What's the Difference Between '$(This)' and 'This'
Asp.Net MVC Jsonresult Date Format
How to Detect Changes in Location Hash
"Cross Origin Requests Are Only Supported For Http." Error When Loading a Local File
How to Make an Ajax Call Without Jquery
How to Execute a JavaScript Function When I Have Its Name as a String
How to Make the First Letter of a String Uppercase in JavaScript
Looping Through Array and Removing Items, Without Breaking For Loop
Selecting Text in an Element (Akin to Highlighting With Your Mouse)
Calling Functions With Settimeout()
How to Add Dynamically Named Properties to JavaScript Object