LoginPage.js
import React, { useState } from 'react'
import Axios from 'axios';
import { useDispatch } from 'react-redux';
import { loginUser } from '../../../_actions/user_action';
import { withRouter } from 'react-router-dom';
function LoginPage(props) {
const dispatch = useDispatch();
// 여기 안에서 데이터를 변화 시켜줄 땐 state를 변화시켜준다.
const [Email, setEmail] = useState("");
const [Password, setPassword] = useState("");
const onEmailHandler = (e) => {
setEmail(e.currentTarget.value)
}
const onPasswordHandler = (e) => {
setPassword(e.currentTarget.value)
}
const onSubmitHandler = (e) => {
// 로그인 버튼을 누를 때 마다 페이지가 refresh가 되는데 이러면 여기 submitHandler 메소드에서 해야 될 일들을 하지않고 페이지가 리프레쉬 되어버리면서 할 수가 없다.
// 이것을 방지해주기 위해서 밑에 코드를 추가
e.preventDefault();
let body = {
email: Email,
password: Password
}
dispatch(loginUser(body))
.then(response => {
if(response.payload.loginSuccess){
props.history.push('/')
} else {
alert('error')
}
})
}
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 withRouter(LoginPage)
위 코드에서 userState를 이용해서 Email과 Password state를 각각 만들어주고 onEmailHandler와 onPasswordHandler 함수를 구현한 후, input태그에 value값과 onChange에 함수를 넣어줬다. 저런식으로 구성하게되면
client에서 Email입력창이나 Password입력창에 어떤걸 입력할 때 그대로 입력되는 것을 확인할 수 있다.
다음은 onSubmitHandler을 알아볼 차례다.
onSubmitHandler는 submit type의 버튼이 눌러졌을 때 form태그를 통해 호출되는 함수이다.
위 내용을 이해하기 위해선 redux 구조를 알아야한다.
*Store*
- Store(스토어)는 상태가 관리되는 오직 하나의 공간이다.
*Action*
- Action(액션)은 앱에서 스토어에 운반할 데이터를 말한다. (주문서)
- Action(액션)은 자바스크립트 객체 형식으로 되어있다.
*Reducer*
- Action(액션)을 Store(스토어)에 바로 전달하는 것이 아니다.
- Action(액션)을 Reducer(리듀서)에 전달해야한다.
- Reducer(리듀서)가 주문을 보고 Store(스토어)의 상태를 업데이트하는 것이다.
- Action(액션)을 Reducer(리듀서)에 전달하기 위해서는 dispatch() 메소드를 사용해야한다.
Action(액션) 객체가 dispatch() 메소드에 전달된다.
dispatch(액션)를 통해 Reducer를 호출한다.
Reducer는 새로운 Store 를 생성한다.
위 내용이 이해됐다면 코드도 쉽게 알 수 있다.
action에 타입이 많이 존재할 수 있으니 타입을 따로 types.js 파일로 분리해서 관리해주자.
액션이 없었다면 컴포넌트에서 직접 axios를 이용하여 서버에 데이터를 요청했겠지만, 리덕스를 사용해야하기 때문에 이 작업을 action에서 하는거다.
위 코드를 실행하면 서버로부터 받아온 response.data가 request에 저장된다.
return 부분에서 payload가 바로 액션이다. 즉, user_reducer을 호출 할 때 (state, action) 이런식으로 매개변수를 주는데, 첫번째 매개변수인 state는 LOGIN_USER이고, 두번째 매개변수인 action부분이 request이다.
위 코드에서 ...state 부분이 있는데, 이것은 spread 연산자라고 한다. 기존에 있던 state들을 원본에 영향을 끼치지 않고 사본을 떠와서 그대로 갖고온다. 스프레드 연산자를 이용해서 state들을 모두 갖고 온 다음, 바뀔 부분을 고치고 업데이트를 해준다는 의미이다.
LoginPage.js에서 action과 dispatch를 갖고온다.
dispatch를 이용해서 action을 reducer에 전달한다.
reducer는 주문서를 보고 store의 상태를 업데이트한다.
이 두 가지가 위 코드들의 과정이다.
body 객체에 현재 입력된 이메일과 비밀번호값을 저장하고, 이 body를 loginUser 매개변수로 넣어준다.
이렇게 되면 user_action.js에서 body값이 dataToSubmit 변수에 담긴다.
전달 받은 이 데이터를 axios를 이용해서 서버에 보낸다.
그리고 서버로부터 어떤 데이터를 받는데, 이 데이터엔 로그인 성공 여부와 userId가 담겨있다.
user_action.js에서 이 데이터를 payload에 넣고, type에는 LOGIN_USER을 넣어서 리턴을 시킴으로써 리듀서 즉, user_reducer을 호출한다.
이렇게되면 user_reducer.js에서 처음에 state={}으로 아무것도 없도록 초기화해주었던 state 변수엔 LOGIN_USER가 들어가고, action에는 payload가 들어가게 된다.
action.type에는 LOGIN_USER가 들어가 있으므로 첫번째 case에 포함된다. 이러면 리듀서는 state를 업데이트한다.
회원가입 페이지는 로그인 페이지랑 거의 비슷하므로 코드만 올려서 나중에 코드만 봐도 좋을 것 같다.
types.js
export const LOGIN_USER = 'login_user';
export const REGISTER_USER = 'register_user';
user_action.js
import Axios from 'axios';
export function loginUser(dataToSubmit) {
const request = Axios.post('/api/users/login', dataToSubmit)
.then(response =>
response.data
)
return {
type: 'LOGIN_USER',
payload: request //옵션
}
}
export function registerUser(dataToSubmit) {
const request = Axios.post('/api/users/register', dataToSubmit)
.then(response =>
response.data
)
return {
type: 'REGISTER_USER',
payload: request //옵션
}
}
user_reducer.js
import {
LOGIN_USER,
REGISTER_USER
} from "../_actions/types";
export default function (state = {}, action) {
switch (action.type) {
case LOGIN_USER:
return { ...state, loginSuccess: action.payload }
case REGISTER_USER:
return { ...state, registerSuccess: action.payload}
default:
return state;
}
}
RegisterPage.js
import React, { useState } from 'react'
import { useDispatch } from 'react-redux';
import { registerUser } from '../../../_actions/user_action';
import { withRouter } from 'react-router-dom';
function RegisterPage(props) {
const dispatch = useDispatch();
// 여기 안에서 데이터를 변화 시켜줄 땐 state를 변화시켜준다.
const [Email, setEmail] = useState("");
const [Name, setName] = useState("");
const [Password, setPassword] = useState("");
const [ConfirmPassword, setConfirmPassword] = useState("");
const onEmailHandler = (e) => {
setEmail(e.currentTarget.value)
}
const onNameHandler = (e) => {
setName(e.currentTarget.value)
}
const onPasswordHandler = (e) => {
setPassword(e.currentTarget.value)
}
const onConfirmPasswordHandler = (e) => {
setConfirmPassword(e.currentTarget.value)
}
const onSubmitHandler = (e) => {
// 로그인 버튼을 누를 때 마다 페이지가 refresh가 되는데 이러면 여기 submitHandler 메소드에서 해야 될 일들을 하지않고 페이지가 리프레쉬 되어버리면서 할 수가 없다.
// 이것을 방지해주기 위해서 밑에 코드를 추가
e.preventDefault();
if (Password != ConfirmPassword) {
return alert('비밀번호가 같지 않습니다.')
}
let body = {
email: Email,
name: Name,
password: Password
}
dispatch(registerUser(body))
.then(response => {
if(response.payload.registerSuccess){
props.history.push('/login')
} else {
alert('error')
}
})
}
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>ComfirmPassword</label>
<input type="password" value={ConfirmPassword} onChange={onConfirmPasswordHandler} />
<br />
<button type="submit">
register
</button>
</form>
</div>
)
}
export default withRouter(RegisterPage)
로그아웃 페이지는 간단하다.
그냥 로그아웃 버튼 하나 만들고, onClick event에 onClickHandler 함수를 구현한 후 넣어서 이 함수를 통해 axios로 server에 logout 요청 코드만 넣어주면 된다.
LandingPage.js
import React, {useEffect} from 'react'
import axios from 'axios';
import {withRouter} from 'react-router-dom'
function LandingPage(props) {
const onClickHandler = () => {
axios.get('/api/users/logout')
.then(response => {
if(response.data.success){
props.history.push('/login')
} else {
alert('로그아웃 하는데 실패하였습니다.')
}
})
}
return (
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', width: '100%', height: '100vh' }}>
<h2>시작 페이지</h2>
<button onClick={onClickHandler}>
logout
</button>
</div>
)
}
export default withRouter(LandingPage)
'boilerplate > Jhon-Ahn boilerplate frontend' 카테고리의 다른 글
Auth (0) | 2023.01.10 |
---|---|
React Hooks (0) | 2023.01.06 |
Redux (0) | 2023.01.06 |
Proxy Server & Concurrently & Antd CSS FrameWork (0) | 2023.01.04 |
React Router Dom & 데이터 flow, Axios & CORS 이슈, Proxy설정 (1) | 2023.01.03 |