https://youtu.be/dFqb4KvRpNA?si=-2b0Bpht-CzUoqKA
본 포스팅은 John Ahn님의 유튜브 강의를 참고했습니다.
안녕하세요 오랜만에 왔네요 : )
오늘은 로그인 기존에 만들던 로그인 기능을 마무리 해보려고 합니다.
먼저 코드를 보여드리고 해석해보겠습니다.
import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { loginUser } from '../../../_actions/user_action';
import { useNavigate } from 'react-router-dom';
function LoginPage() {
const dispatch = useDispatch();
const navigate = useNavigate(); // Hook from React Router
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const onEmailHandler = (event) => {
setEmail(event.currentTarget.value);
};
const onPasswordHandler = (event) => {
setPassword(event.currentTarget.value);
};
const onSubmitHandler = (event) => {
event.preventDefault();
const body = {
email: email,
password: password,
};
dispatch(loginUser(body))
.then((response) => {
if (response.payload.loginSuccess) {
navigate('/'); // Use navigate instead of props.history.push
} else {
alert('Error');
}
})
.catch((error) => {
console.error('Login error:', error);
alert('Login failed. Please try again.');
});
};
return (
<div
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: '100vh',
}}
>
<form
style={{ display: 'flex', flexDirection: 'column' }}
onSubmit={onSubmitHandler}
>
<label>Email</label>
<input type="email" value={email} onChange={onEmailHandler} />
<label>Password</label>
<input type="password" value={password} onChange={onPasswordHandler} />
<br />
<button type="submit">Login</button>
</form>
</div>
);
}
export default LoginPage;
로그인 페이지의 코드입니다.
return (
<div
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: '100vh',
}}
>
<form
style={{ display: 'flex', flexDirection: 'column' }}
onSubmit={onSubmitHandler}
>
<label>Email</label>
<input type="email" value={email} onChange={onEmailHandler} />
<label>Password</label>
<input type="password" value={password} onChange={onPasswordHandler} />
<br />
<button type="submit">Login</button>
</form>
</div>
);
}
스타일은 가운데에 위에서 아래로 정렬되게 되있습니다.
form에 onSubmitHandler함수를 적용해서 버튼을 눌러 제출할 시
새로고침이 되는것을 방지했습니다.
input은 Email과 Password가 있는데 input창에 상태가 변경되면,
즉 데이터가 입력되면
각각 onEmailHandler와 onPasswordHandler를 발생시킵니다.
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const onEmailHandler = (event) => {
setEmail(event.currentTarget.value);
};
const onPasswordHandler = (event) => {
setPassword(event.currentTarget.value);
};
각 함수들은 useState기능을 활용해서
input으로 들어오는 데이터를 서버의 데이터로 변환하여 저장합니다.
const body = {
email: email,
password: password,
};
dispatch(loginUser(body))
.then((response) => {
if (response.payload.loginSuccess) {
navigate('/'); // Use navigate instead of props.history.push
} else {
alert('Error');
}
})
.catch((error) => {
console.error('Login error:', error);
alert('Login failed. Please try again.');
});
};
body를 정의해서 데이터의 형식을 정의하고
redux의 dispatch함수를 이용해서 loginUser동작이 loginSucceess를 반환한다면
useNavigate함수를 이용해서 처음에 있던 landing페이지로 돌아갑니다.
로그인에 실패한다면 에러메세지를 띄웁니다.
localhost:3000/login
이것이 로그인 페이지의 UI입니다.
Email과 Password를 입력하면 로그인을 진행합니다.
Postman
지금은 회원가입 기능이 없으니
Postman으로 회원가입을하고 로그인을 진행해보겠습니다.
위 화면에서는 success : true를 반환하였으므로
해당 email과 password로 회원가입이 된 것입니다.
로그인 버튼을 눌렀을 때
로그인 버튼을 누르면 이렇게 시작 페이지로 이동하게 됩니다.
로그인이 성공적으로 된 것입니다.
다음은 회원가입 페이지를 만들어보겠습니다.
app.post('/api/users/register', async (req, res) => {
try {
const user = new User(req.body);
await user.save();
return res.status(200).json({
success: true
});
} catch (error) {
return res.json({ success: false, error });
}
});
서버에서 user의 데이터가 들어오면 새로운 유저의 데이터로 저장해줍니다.
import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { registerUser } from '../../../_actions/user_action';
import { useNavigate } from 'react-router-dom';
function RegisterPage() {
const dispatch = useDispatch();
const navigate = useNavigate(); // Hook from React Router
const [email, setEmail] = useState('');
const [name, setName] = useState('');
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const onEmailHandler = (event) => {
setEmail(event.currentTarget.value);
};
const onNameHandler = (event) => {
setName(event.currentTarget.value);
};
const onPasswordHandler = (event) => {
setPassword(event.currentTarget.value);
};
const onConfirmPasswordHandler = (event) => {
setConfirmPassword(event.currentTarget.value);
};
const onSubmitHandler = (event) => {
event.preventDefault();
if (password !== confirmPassword) {
return alert('비밀번호와 비밀번호 확인은 같아야 합니다.');
}
let body = {
email: email,
password: password,
name: name,
};
dispatch(registerUser(body))
.then((response) => {
if (response.payload.success) {
navigate('/login'); // Use navigate instead of withRouter
} else {
alert('Failed to sign up');
}
});
};
return (
<div
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: '100vh',
}}
>
<form
style={{ display: 'flex', flexDirection: 'column' }}
onSubmit={onSubmitHandler}
>
<label>Email</label>
<input type="email" value={email} onChange={onEmailHandler} />
<label>Name</label>
<input type="text" value={name} onChange={onNameHandler} />
<label>Password</label>
<input type="password" value={password} onChange={onPasswordHandler} />
<label>Confirm Password</label>
<input type="password" value={confirmPassword} onChange={onConfirmPasswordHandler} />
<br />
<button type="submit">
회원 가입
</button>
</form>
</div>
);
}
export default RegisterPage;
회원가입페이지는 로그인 페이지와 상당 부분이 비슷합니다.
<form
style={{ display: 'flex', flexDirection: 'column' }}
onSubmit={onSubmitHandler}
>
<label>Email</label>
<input type="email" value={email} onChange={onEmailHandler} />
<label>Name</label>
<input type="text" value={name} onChange={onNameHandler} />
<label>Password</label>
<input type="password" value={password} onChange={onPasswordHandler} />
<label>Confirm Password</label>
<input type="password" value={confirmPassword} onChange={onConfirmPasswordHandler} />
<br />
<button type="submit">
회원 가입
</button>
</form>
회원가입시 필요한 Name과 비밀번호를 확인하기위해 Confirm Password가 추가되었고
const onEmailHandler = (event) => {
setEmail(event.currentTarget.value);
};
const onNameHandler = (event) => {
setName(event.currentTarget.value);
};
const onPasswordHandler = (event) => {
setPassword(event.currentTarget.value);
};
const onConfirmPasswordHandler = (event) => {
setConfirmPassword(event.currentTarget.value);
};
Handler함수도 추가되었습니다.
if (password !== confirmPassword) {
return alert('비밀번호와 비밀번호 확인은 같아야 합니다.');
}
만약 password가 confirmPassword와 다르다면 에러메세지를 띄웁니다.
let body = {
email: email,
password: password,
name: name,
};
dispatch(registerUser(body))
.then((response) => {
if (response.payload.success) {
navigate('/login'); // Use navigate instead of withRouter
} else {
alert('Failed to sign up');
}
});
};
데이터 형식이 변했으므로 body를 새로 정의하고
서버의 유저등록 동작을 요청합니다.
성공하면 로그인페이지로 이동하고
실패하면 에러메세지를 띄웁니다.
user_action.js에서
export function registerUser(datetoSubmit)
{
const request = axios.post('/api/users/register', datetoSubmit)
.then(response =>
response.data
)
return{
type: "REGISTER_USER",
payload : request
}
}
post요청을 하기위해 request를 새로 정의해줍니다.
export default function(state = {}, action){
switch(action.type){
case LOGIN_USER:
return{...state, loginSuccess : action.payload}
break;
case REGISTER_USER:
return{...state, register : action.payload}
break;
default:
return state;
break;
}
리듀서에서도 REGISTER_USER를 만들어 줘서
데이터를 업데이트 할 수 있게 해줍니다.
그럼 이제 회원가입을 할 준비가 되었습니다.
RegisterPage
회원가입이 성공하면
성공한 계정으로 로그인을 시도해봅니다.
회원가입된 계정으로 로그인이 성공한다면 시작페이지로 돌아갈 것입니다.
Landing Page
오늘은 이렇게 기존에 서버에 만들었던
Login과 Register 기능을 가지고
직접 동작할 수 있게 구현까지 해보았습니다.
긴 글 읽어주셔서 감사합니다!
