Mohammad Faateh
Mohammad Faateh

Reputation: 145

Update state of array variable

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

Answers (2)

Yoshi
Yoshi

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:

  1. 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.

  2. 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?

  1. use useEffect appropriately.

  2. 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

Piyush Mahapatra
Piyush Mahapatra

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

Related Questions