[Node.js] 로그인 페이지 구현

권규리·2024년 3월 5일

🧱Node.js

목록 보기
10/15

👩🏻‍💻 여는 말

Node.js로 간단하게 서버 api 만들고, 프론트에 연결시키는 과정을 해보았다!!
처음으로 직접 만든 api를 사용하는 거라 신기하고 흥미롭군 . . . 로그인 페이지 하면 다른 페이지들도 구현해봐야겠다 ✨

(1) Server

⭐ index.js

우선 MONGO DB에 이메일과 비밀번호를 이용하여 회원가입을 해놓은 상태기 때문에, Client 단에서 form을 구현 후 DB에 있는 이메일과 비밀번호를 가져다 로그인을 해볼 것이다.

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

    try{
        // client로부터 요청된 이메일이 DB에 있는지 확인
        const user= await User.findOne({ email: req.body.email })

        if(!user){
            return res.json({
                loginSuccess: false,
                message: "요청받은 이메일에 해당하는 유저가 없습니다."
            })
        }

        // 요청된 이메일이 있다면, 비번이 맞는지 확인
        const isMatch= await user.comparePassword(req.body.password);
        if(!isMatch){
            return res.json({ loginSuccess: false, message: "비밀번호가 틀렸습니다." }) 
        }

        // 비번이 맞다면, 토큰 생성
        const userdata= await user.generateToken();
        res
            .cookie("x_auth",user.token)
            .status(200)
            .json({loginSuccess:true, userId: user._id})
    } catch(err){
        return res.status(400).send(err)
    }
})

(2) Client

⭐ LoginPage.js

import React, { useState } from 'react'
import { useDispatch } from 'react-redux';
import { loginUser } from '../../../_actions/user_action';
import { useNavigate } from 'react-router-dom';

export default function LoginPage() {
    const [email, setEmail]= useState('');
    const [password, setPassword]= useState('');
    const dispatch= useDispatch();
    const navigate= useNavigate();

    const hadleSubmit= async(e)=>{
        e.preventDefault();

        // 서버로 보낼 정보 담기
        let user= {
            email: email,
            password: password,
        }

        dispatch(loginUser(user))
        .then(response=> {
            if(response.payload.loginSuccess){
                navigate('/');
            }else{
                alert('Error')
            }
        })
    }

    return (
        <div style={{display: 'flex', justifyContent:'center',alignItems:'center',
        width:'100%', height:'100vh'}}>
            <form style={{display:'flex', flexDirection:'column', gap:'30px'}}>
                <label>이메일</label>
                <input type='email' value={email} onChange={(e)=>{
                    setEmail(e.target.value);
                }}></input>

                <label>비밀번호</label>
                <input type='password' value={password} onChange={(e)=>{
                    setPassword(e.target.value);
                }}></input>

                <button onClick={hadleSubmit}>로그인</button>
            </form>
        </div>
    )
}

dispatch를 통해 reducer에게 state를 수정하라고 해야한다. 이때 reducer는 이전 state값과 action의 type을 받아 새로운 state값을 반환하여 state값이 바뀌는 것이다.

⭐ user_action.js

import axios from "axios";
import { LOGIN_USER } from './types'

// login 페이지에서 받아온 정보를 파라미터에 넣어줌
export async function loginUser(dataToSubmit){
    const request= await axios.post('/api/users/login', dataToSubmit)
        .then(response => response.data)

    return{
        type: LOGIN_USER,
        payload: request
    }

}

action에서는 axios로 서버와 통신을 성공하면, 이건 로그인에 관한 통신이야~ 하고 알려주는 type을 반환해준다. 이러한 type은 새로운 state 값을 주는 reducer에게 필요한 정보이다.

⭐ user_reducer.js

import { LOGIN_USER } from "../_actions/types";

// reducer의 인자는 (previousState, action)
export default function(state= {}, action){
    switch (action.type){
        case LOGIN_USER:
            return{...state, loginSuccess: action.payload}
        break;

        default:
            return state;
    }
}

이전 state값과 action의 type을 받은 reducer는 switch문으로 알맞은 action.type을 찾고, 새로운 state값을 반환해준다 !! 위의 코드에서 새로운 state 값은 {...state, loginSuccess: action.payload} 이다. action.payload는 user_action.js에서 request의 성공 유무를 나타낸다.
이런식으로 loginSuccess : 성공 여부 가 나타난다.

profile
기록장 📝

0개의 댓글