Archive

Auth Boiler Plate View with React,Redux - Login

|

Boiler Plate with React,Redux - Login


Login View Page

Node.js 로 구현한 로그인 기능을 실질적으로 눈으로 확인하기 위해 view 페이지를 만든다

view는 react로 구현하고 상태관리는 redux를 이용한다

또, 빠른 실습을 위해 create-react-app으로 빌드한다

먼저, 간단한 로그인창을 만들고 input태그에 onChange 이벤트, form 태그에 onSubmit 이벤트를 걸어준다

onSubmit시 action을 dispatch한다

// LoginPage.js
import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { loginUser } from '../../../_actions/user_action';

function LoginPage(props) {
    const dispatch = useDispatch(); 
    
    const [Email, setEmail] = useState('');
 	const [Password, setPassword] = useState('');
    
    // Email onChange Event
    const onEmailHandler = (e) => {
      setEmail(e.currentTarget.value);
    };
    // Password onChange Event
    const onPasswordHandler = (e) => {
      setPassword(e.currentTarget.value);
    };
    // onSubmit Event
    const onSubmitHandler = (e) => {
      e.preventDefault();
        
	  // Request Body 생성
      let body = {
        email: Email,
        password: Password,
      };
	  // action에서 axios 요청을 실시하고 return값으로 응답을 받음
      dispatch(loginUser(body)).then((response) => {
        if (response.payload.loginSuccess) {
          props.history.push('/');
        } else {
          alert('Login Fail!');
        }
      });
    };
    return (
    <div>
      <form
        onSubmit={onSubmitHandler}
      >
        <label>Email</label>
        <input type='email' value={Email} onChange={onEmailHandler} required />
        <label>Password</label>
        <input
          type='password'
          value={Password}
          onChange={onPasswordHandler}
          required
        />
        <br />
        <button type='submit'>Login</button>
      </form>
    </div>
  );
}
export default LoginPage;
// user_action.js

import axios from 'axios';

export function loginUser(dataSubmit) {
  // LoginPage에서 작성한 body로 axios 요청
  const request = axios
    .post('/api/users/login', dataSubmit)
    .then((response) => {
      return response.data;
    });
  // action의 payload에 response 데이터를 담는다
  return {
    type: 'LOGIN_USER',
    payload: request,
  };
}
// user_reducer.js

export default function (state = {}, action) {
  switch (action.type) {
    case 'LOGIN_USER':
      return {
        ...state,
        loginSuccess: action.payload,
      };
    default:
      return state;
  }
}


reducer는 기능별로 여러개가 나올것이므로 이 흩어져있는 reducer들을 모을 rootReducer가 필요하다

// _reducers/index.js

import { combineReducers } from 'redux';
import user from './user_reducer';

const rootReducer = combineReducers({
  user,
  // 이 곳에 reducer 추가
});

export default rootReducer;

redux 패키지의 combineReducers 메소드를 이용하여 각가의 reducer들을 모아준다


redux에서는 상태를 store라는 하나의 큰 저장소에서 관리하는데, store는 보통 index 등 패키지의 제일 앞단에 설치한다

앞으로 redux-thunk, redux-promise 등의 미들웨어를 사용할 예정이므로 store 생성시 이 미들웨어도 같이 끼워넣어 주어야한다.

store에 인자로 reducer를 넣어주는데, 이를 위해 react-redux 패키지의 Provider로 App 컴포넌트를 감싸준다

// index.js

import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import promiseMiddleware from 'redux-promise';
import ReduxThunk from 'redux-thunk';
import Reducer from './_reducers';

const createStoreWithMiddleware = applyMiddleware(
  promiseMiddleware,
  ReduxThunk
)(createStore);

ReactDOM.render(
  <React.StrictMode>
    <Provider
      store={createStoreWithMiddleware(
        Reducer,
        window.__REDUX_DEVTOOLS_EXTENSION__ &&
          window.__REDUX_DEVTOOLS_EXTENSION__()
      )}
    >
      <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);

window.머시기들은 redux-devtool을 사용하기 위한 환경변수이다


서버 구축시 테스트용으로 미리 넣어놓은 사용자로 로그인을 시도해본다

테스트

로그인 성공시 loginSuccess: true와 서버에서 만들어 보낸 JWT가 state에 잘 저장된 것을 볼 수 있다



참고 자료


기초 노드 리액트 강의 - John Ahn