본문 바로가기

boilerplate/Jhon-Ahn boilerplate frontend

login page & register page & logout

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를 이용해서 EmailPassword state를 각각 만들어주고 onEmailHandleronPasswordHandler 함수를 구현한 후, input태그에 value값과 onChange에 함수를 넣어줬다. 저런식으로 구성하게되면 

 

front

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 파일로 분리해서 관리해주자.

types.js

 

user_action.js

액션이 없었다면 컴포넌트에서 직접 axios를 이용하여 서버에 데이터를 요청했겠지만, 리덕스를 사용해야하기 때문에 이 작업을 action에서 하는거다. 

위 코드를 실행하면 서버로부터 받아온 response.data가 request에 저장된다.

return 부분에서 payload가 바로 액션이다. 즉, user_reducer을 호출 할 때 (state, action) 이런식으로 매개변수를 주는데, 첫번째 매개변수인 state는 LOGIN_USER이고, 두번째 매개변수인 action부분이 request이다.

 

 

 

user_reducer.js

위 코드에서 ...state 부분이 있는데, 이것은 spread 연산자라고 한다. 기존에 있던 state들을 원본에 영향을 끼치지 않고 사본을 떠와서 그대로 갖고온다. 스프레드 연산자를 이용해서 state들을 모두 갖고 온 다음, 바뀔 부분을 고치고 업데이트를 해준다는 의미이다. 

 

 

LoginPage.js에서 action과 dispatch를 갖고온다.

LoginPage.js

 

LoginPage.js

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