3

I want to submit this registeration form with unique names.

First Problem : I can't seem to map third time. The error shows array is not iterable.

Second Problem : I cant change the setArray state in (array not empty) section. I know it is synchronous but I can't seem to find a solution.

Please give me a solution of if I want to have an immediate value of state after changing setState. I'm stuck in this problem for 3 days.

import React from 'react';

import { Paper, Typography, TextField , Button, makeStyles} from '@material-ui/core';

import { Link} from 'react-router-dom'

import {useEffect} from 'react';

const useStyle = makeStyles((theme)=>(

    {
        formWrapper : {
            display : 'flex',
            width : '100%',
            height : '100%',
            alignItems : 'center',
            justifyContent : 'center'
        },
        paper : {
            padding : '20px',
            margin : '20px'
        },
        textfield : {
            marginLeft : '20px',
            marginBottom : '10px'
        },
        span : {
            margin: '10px',
            marginLeft : '20px'
        }

    }
))

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){ // Array is empty
            if((name === null || password === null)||(name === '' || password === '')){ //check if name and password are empty
                alert('Enter username and password')
                
            }else{  // not empty then store in localstorage
                localStorage.setItem('name', name);
                localStorage.setItem('password',password);
                
                obj.id = Math.random();
                obj.name = localStorage.getItem('name');
                obj.password = localStorage.getItem('password');
                setArray(array.push(obj))
                localStorage.setItem('array',JSON.stringify(array))
                setName('');
                setPassword('')
                return alert('You are registered'); 
                
            }
        }
        else  // array not empty
        {
            if((name === null || password === null) ||(name === '' || password === '')){
                alert('Enter username and passsword');
            }

            let array2 = JSON.parse(localStorage.getItem('array')).map(user=> user.name)
            var found = array2.includes(name);
            if(found){
                alert('User name Taken')
                setName('')
                setPassword('')
            }
            else{
                localStorage.setItem('name', name);
                localStorage.setItem('password',password);
                obj.id = Math.random();
                obj.name = localStorage.getItem('name');
                obj.password = localStorage.getItem('password');
                setArray([...array,obj])
                localStorage.setItem('array',JSON.stringify(array))
                console.log(array);
                setName('');
                setPassword('')
                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}  value = {name} name = "username"  label="Username" onChange = {e=>setName(e.target.value)} />
                    <br />
                    <TextField id="password" className={classes.textfield}  value = {password} name = "password"  label="Password" onChange = {e=>setPassword(e.target.value)} />
                    <br />
                    <span className ={classes.span}><Link to="/">Sign In</Link></span>
                    <br />
                    <Button variant="contained" color="secondary" style = {{width : '100%', marginTop : '10px'}} onClick = {submit} >Register </Button>
                </form>
                </Paper>
            </div>
        </div>
    
    )
}

 
export default Register;
zmag
  • 7,825
  • 12
  • 32
  • 42
  • You really sure you want to save users password to localStorage and in plain text? See this conversation: https://stackoverflow.com/questions/3718349/html5-localstorage-security – drodil Jul 01 '21 at 05:45

1 Answers1

2

setArray(array.push(obj)) is a state mutation and array.push returns the new length of the array. Add an element to the array, similar to what you did in the else branch. React state updates are asynchronous so you can't wait for the state to update before persisting it to local storage.

const newArray = [...array, obj];
setArray(newArray);
localStorage.setItem('array', JSON.stringify(newArray));

Alternatively you should probably just enqueue the state updates and then use an useEffect hook to do the persisting once state is updated.

setArray([...array, obj]);

...

useEffect(() => {
  localStorage.setItem('array', JSON.stringify(array));
}, [array]);

Update

Since you are persisting local state to localStorage then you will want to also initialize the local state from localStorage. Use a lazy state initializer function to read in from localStorage and return the initial state value.

const [array, setArray] = React.useState(() => {
  const initialState = localStorage.getItem('array');
  return JSON.parse(initialState) || [];
});

If JSON.parse(initialState) returns a value then this will be the initial array state value, otherwise if there is nothing stored in localStorage null will be computed value and the || [] will return an empty array ([]) as the initial array state value.

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • I tried this useEffect but when I go to SIgnIn page and back to register page, it refreshes array back to 0 in localStorage – Mohammad Faateh Jul 01 '21 at 05:57
  • 1
    @MohammadFaateh This is because the component remounts and the initial `array` state is an empty array (`[]`). If you are persisting state to localStorage then you probably want to initialize state from localStorage. If you need help with this I can update my answer to reflect that. – Drew Reese Jul 01 '21 at 06:03
  • @MohammadFaateh Done. Please check the update to my answer. – Drew Reese Jul 01 '21 at 06:08
  • Thank you so much. Can you also please explain this code? i'd be really grateful – Mohammad Faateh Jul 01 '21 at 06:10
  • The code that you updated. I have a question. what value will localstorage get and store it in initialState. And second what does this statement mean 'JSON.parse(initialState || []'? – Mohammad Faateh Jul 01 '21 at 06:13
  • 1
    @MohammadFaateh Ok, added a brief explanation, hopefully that makes clear what the initializer function is doing. – Drew Reese Jul 01 '21 at 06:17
  • Sir one other problem arose. When i register the first user, it stores empty array in localStorage. When i store second user, it stores first user in array in localStorage – Mohammad Faateh Jul 01 '21 at 06:21
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/234394/discussion-between-drew-reese-and-mohammad-faateh). – Drew Reese Jul 01 '21 at 06:28