Reputation: 145
I want to change the state of setArray but I cant change it. The console.log shows empty array. The other states are working but not this I've used useEffect too but nothing is happening. Kindly give me a solution.
import React from 'react';
import { Link} from 'react-router-dom'
import {useEffect} from 'react';
const Register = () =>{
const classes = useStyle();
const [name, setName] = React.useState('');
const [password, setPassword] = React.useState('');
const [array, setArray] = React.useState([])
const submit = (event) =>{
const obj = {}
event.preventDefault();
if(array.length === 0){
localStorage.setItem('name', name);
localStorage.setItem('password',password);
localStorage.setItem('array',JSON.stringify(array))
obj.id = Math.random();
obj.name = localStorage.getItem('name');
obj.password = localStorage.getItem('password');
setArray(array => [...array,obj])
console.log(array);
return alert('You are registered');
}
}
return(
<div>
<div className = {classes.formWrapper}>
<Paper elevation={3} className = {classes.paper} >
<Typography variant="h5" style = {{ textAlign : 'center'}}>Register</Typography>
<form noValidate autoComplete="off">
<TextField id="username" className={classes.textfield} style={{width : '95%'}} value = {name} name = "username" label="Username" onChange = {e=>setName(e.target.value)} />
<br />
<TextField id="password" className={classes.textfield} style={{width : '95%'}} value = {password} name = "password" label="Password" onChange = {e=>setPassword(e.target.value)} />
<br />
<br />
<Link to='/'>SignIn</Link>
<Button variant="contained" color="secondary" style = {{width : '100%'}} onClick = {submit} >Register </Button>
</form>
</Paper>
</div>
</div>
)
}
export default Register;
Upvotes: 0
Views: 143
Reputation: 54649
To clarify, the reason why console.log(array);
logs the old array is not because setArray
(or rather, it's implementation) is or is not asynchronous. It is because, simply put, it's impossible.
And even if it were fully synchronous, it would still be so.
The reason:
Javascript is a pass-by-value (or rather call-by-sharing), or more importantly not a pass-by-reference language. This means, that there is absolutely no way to implement setArray
in such a way that it could change what is assigned to array
. A dead giveaway that you shouldn't even assume this was possible, is that array
is a const
.
Except from throwing an exception, it is impossible to prevent the execution of the remaining code after setArray(array => [...array,obj])
from inside setArray
.
Also note, that this is not a react thing. It's simply a part of the language as is. So there's also no way to fix this (not that I'm saying a fix is needed).
So what is really happening? Quit simple:
const submit = (event) => { ... }
forms a closure over the constant array
. And thus console.log(array);
must refer to that value. That setArray(array => [...array,obj])
stages a state update for the next render, and whether that process is synchronous or asynchronous, is completely irrelevant here.
So how to refer to a changed state variable?
use useEffect
appropriately.
use the value you would want to assign as the new state where you calcualte it. E.g.:
setArray(array => {
const next = [...array, obj];
console.log(next); // new value
return next;
});
console.log(array); // *still* the old value, for the above mentioned reasons
Upvotes: 2
Reputation: 223
setState is asynchronous. It means you can’t call it on one line and assume the state has changed on the next.
From React 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. There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.
Upvotes: 0