skip to Main Content

I am building a user login system and currently the way I have it set up, the user types in their email and password and then that information is sent to my server to be checked if accurate. If it is, I create a JWT token and send it back along with the mongodb _id of the user, I then in another request use the mongodb _id of the user from the first request to retrieve all the information (blogs in this case) associated with their mognodb _id. All of this works except for the issue I am running into is the axios request does not work the first time. So I have to hit submit to log in for an error to occur TypeError: Cannot read properties of undefined (reading 'data') and then when I hit submit again it works. I believe the problem is getBasic not getting set before the rest of the code runs on the first attempt, and on the second attempt it is already defined. I am not sure how I can fix this without maybe a manual timer before I do the getBasic.data.map, but I know there must be a better way to fix this.

And just to add this is just me trying to test this concept so I understand later things like bcrypt will need to be added to the password instead of plaintext in the database, etc.

Frontend:

 function Login() {
    
    const [user, setUser] = useState()
    const [getBasic, setGetBasic] = useState()

    const [Item, setItem] = useState({
        email: '',
        password: ''
    });

    async function fetchData() {
        const sentItem = {
            user: user.data.user._id,
        }

        await axios.post('http://localhost:3001/api', sentItem)
            .then(result => setGetBasic(result))
    }



    const loginFunc = async () => {
        const checkUser = {
            email: Item.email,
            password: Item.password
        }

        await axios.post('http://localhost:3001/api/login', checkUser)
            .then(result => setUser(result))
            .then(fetchData())  
    }







    if (user && getBasic) {

        localStorage.setItem('key', JSON.stringify(user.data.token))
        console.log(localStorage.getItem('key'))

        return (
            <div>
                <div>
                    <input onChange={handleChange} name="email" value={Item.email} placeholder="email" />
                    <input onChange={handleChange} name="password" value={Item.password} placeholder="password" />
                    <button onClick={loginFunc}>Submit</button>

                </div>


                {
                    getBasic.data.map(({ text, _id, }, i) => {
                        return (
                            <div>
                                <p>{_id}</p>
                                <p>{text}</p>
                            </div>
                        );
                    })
                }   
        )
    }
    return (

        <div>

            <input onChange={handleChange} name="email" value={Item.email} placeholder="email" />
            <input onChange={handleChange} name="password" value={Item.password} placeholder="password" />
            <button onClick={loginFunc}>Submit</button>

        </div>
    )
}

export default Login

Server:

app.post('/api/login', async (req, res) => {


    const user1 = await User.findOne({ email: req.body.email, password: req.body.password })

    if (user1) {
        const payload = { name: req.body.name, email: req.body.email };
        const token = jwt.sign(payload, private_key, { expiresIn: '200s' });
        console.log('correct login')
        res.status(200).send({ auth: true, token: true, user: user1 })

    } else {
        console.log('incorrect login')
    }

})


app.post('/api', async (req, res) => {

    Blog.find({ user: req.body.user }, function (err, result) {
        if (err) {
            console.log(err)
        } else {
            res.send(result)
        }
    })

})

3

Answers


  1. While nature of React.useState is asynchronous, and changes will not be reflected immediately, closures take their role in situations like this, as pointed out in link in below.

    More details provided here – The useState set method is not reflecting a change immediately

    As stated in error from your example, cannot read data of undefined – meaning user is undefined, and you try to access to user.data which leads to error.

    const sentItem = {
        user: user.data.user._id,
    }
    

    Instead of

    await axios.post('http://localhost:3001/api/login', checkUser)
                .then(result => setUser(result))
                .then(fetchData())  
    

    why don’t you try this (remove fetchData function if not reused on other places…):

    const result = await axios.post('http://localhost:3001/api/login', checkUser);
    const sentItem = {
       user: result.data.user._id,
    }
    axios.post('http://localhost:3001/api', sentItem)
            .then(result => setGetBasic(result));
    
    setUser(result);
    
    Login or Signup to reply.
  2. I think you should create user state like this

    const [user, setUser] = useState({})

    Login or Signup to reply.
  3. .then(fetchData())

    The then method accepts a function which runs when the other stuff is done. However, you are not passing in a function here, but the return result from calling fetchData.

    Try
    .then(fetchData)

    or

    .then(() => fetchData())

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search