
Node.js로 간단하게 서버 api 만들고, 프론트에 연결시키는 과정을 해보았다!!
처음으로 직접 만든 api를 사용하는 거라 신기하고 흥미롭군 . . . 로그인 페이지 하면 다른 페이지들도 구현해봐야겠다 ✨
우선 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)
}
})
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값이 바뀌는 것이다.
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에게 필요한 정보이다.
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 : 성공 여부 가 나타난다.