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페이지로 돌아갑니다.
로그인에 실패한다면 에러메세지를 띄웁니다.
이것이 로그인 페이지의 UI입니다.
Email과 Password를 입력하면 로그인을 진행합니다.
지금은 회원가입 기능이 없으니
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를 만들어 줘서
데이터를 업데이트 할 수 있게 해줍니다.
그럼 이제 회원가입을 할 준비가 되었습니다.
회원가입이 성공하면
성공한 계정으로 로그인을 시도해봅니다.
회원가입된 계정으로 로그인이 성공한다면 시작페이지로 돌아갈 것입니다.
오늘은 이렇게 기존에 서버에 만들었던
Login과 Register 기능을 가지고
직접 동작할 수 있게 구현까지 해보았습니다.
긴 글 읽어주셔서 감사합니다!