반응형

HOC(Higher Order Component)

: 다른 컴포넌트를 받은 다음에, 새로운 컴포넌트를 반환한다.

: 받은 컴포넌트가 인증된 것만 새로운 컴포넌트를 반환해준다.

 

만약, 이미 로그인한 상태였다면 로그인 페이지가 아닌 다른 페이지를 반환해줘야 한다.

 

 

1. auth.js 에서 로그인한 상태로는 들어갈 수 없거나, 관리자 권한 없이는 들어가지 못하는 경우를 처리해준다.

 

만약 로그인하지 않았는데 option이 true라 로그인한 유저만 출입가능하다면,

로그인 페이지로 이동

 

만약 로그인하였는데 관리자만 들어갈 수 있는 페이지이고, 나는 관리자가 아니라면

landing page로 이동

 

만약 로그인하였는데 option이 false라서 로그인한 유저는 출입 불가능이라면

landing page로 이동

 

import React, {useEffect} from 'react';
import { useDispatch } from 'react-redux';
import { auth } from '../_actions/user_action';

export default function ( SpecificComponent, option, adminRoute = null ){       // adminRoute 는 관리자만 들어갈수있는

    // option //
    // null : 아무나 출입가능
    // true : 로그인한 유저만 출입가능
    // false : 로그인한 유저는 출입불가능

    function AuthenticationCheck(props){

        const dispatch = useDispatch();
        

        useEffect(() => {
            
            dispatch(auth()).then(response => {
                console.log(response);

                // 로그인 하지 않은 상태
                if(!response.payload.isAuth){
                    if(option){
                        props.history.push('/login');
                    }
                } else {
                    // 로그인 한 상태
                    if(adminRoute && !response.payload.isAdmin){
                        props.history.push('/');
                    } else {
                        if(option === false){
                            props.history.push('/');
                        }
                    }
                }
            })

            
        }, [])

        return (
            <SpecificComponent />
        )
    }
    return AuthenticationCheck
}

auth.js

 

 

반응형
반응형

1. Spring와 Node.js

Spring은 Java를 이용하는 프레임워크이고, Node.js는 Javascript 런타임이다. 둘 다 서버 개발을 할 수 있다.

2. 차이점 

2-1. Spring

장점

  • 크기와 부하의 측면에서 경량이다.
  • Spring이 안정적이라는 말을 많이 한다. 그 이유는 레퍼런스가 많아 이슈를 쉽게 해결할 수 있고, 자유성이 낮다는 점에서 안정적이라고 생각한다.
  • 스프링은 2002년 로드 존슨이 최초로 개발하였기에 Spring을 다루는 개발자가 많아 인력 문제도 없다.
  • 많은 개발자들이 오랫동안 사용하고 유지해왔기 때문에 알려진 버그와 보안 문제는 많이 잡혀있어서 안정성이 우수하다.
  • 정형화된 패턴이 있다.
  • IOC/ DI로 느슨한 결합도를 유지한다.
  • 자유도는 낮지만 안정적이다.

단점

  • 설정이 복잡한 편이다.

 

 

 

2-2. node.js

장점

  • V8 엔진을 기반으로 한 성능이 뛰어나다.
  • 싱글스레드, 비동기 IO 처리에 기반한 빠른 속도를 가진다.
  • 파일 I/O나 네트워크 처리를 이벤트 드리븐 방식으로 처리하기 때문에 빠른 처리가 가능하다.
  • CPU의 대기시간을 최소화 할 수 있다.
  • CPU 부하가 적고, 많은 커넥션을 동시에 처리해야 하는 구조에 적합하다.
  • 자바스크립트를 이용해서 개발할 수 있기 때문에 프론트엔드 개발자의 진입장벽이 낮다.
  • 기존 Java 서버에 비해 생산성이 훨씬 높다.

단점

  • 싱글스레드 모델이기 때문에 하나의 작업에 시간이 오래걸리면 시스템 전체의 성능이 급격하게 떨어진다.
  • 에러가 발생할 경우 프로세스 자체가 죽어버리므로 주의해야한다.(watch dog 등으로 처리 가능)
  • 멀티코어 활용을 위해서 cluster 모듈을 이용해야 하고, 세션을 공유할 경우 부가적인 작업이 필요하다.
  • 비동기 제어가 까다롭다.

 

 

 

 

3. 주요특징

Spring MVC의 다중요청 처리

Spring MVC는 Thread를 여러개 두어 (Multi-Thread) 다중요청을 동시에 처리합니다. 각 요청마다 별개의 Thread가 해당 요청을 응답까지 책임지는 구조입니다. 

 

마치 식당에서 여러명의 웨이터(server)가 여러 손님(client)들의 요청을 하나씩 분담하는 구조입니다. 이러한 방식에서 많은 웨이터를 두면 손쉽게(?) 많은 손님들의 요청을 동시에 처리할 수 있습니다. 다만, 일반적인 식당에서는 웨이터가 손님을 직접적으로 대응하는 시간보다 주방(kitchen)에서 음식을 조리하는 시간이 더 오래 걸리기 마련입니다. 주방에서 조리하는 시간에 웨이터들은 음식이 나오기만을 하염없이 기다린다면 식당 주인 입장에서 자원의 낭비가 수반되는 방식입니다.

 

Spring MVC의 Multi-Thread방식에서 I/O 작업이 수반된다면 위의 예제와 같은 자원의 낭비가 발생됩니다. Thread가 수행하는 요청과 응답에 대한 일처리에 비하여, I/O 작업은 훨씬 긴 작업시간을 가지고 있고 이러한 시간동안 Thread들이 블로킹되기 때문입니다. Thread의 갯수가 증가될때마다 컨텍스트 스위칭이 빈번하게 일어나게 될 것이고 이로 인한 성능 저하도 야기 될 수 있습니다. 

 

 

 

Node.js의 다중요청 처리

반면에 Node.js는 단 한개의 Thread로 (Single-Thread) 모든 요청을 처리합니다.

 

한개의 Thread만으로도 Spring MVC의 처리속도와 비견될 수 있는 이유는 Node.js가 완전한 비동기-논블러킹 방식의 I/O 작업을 수용하기 때문입니다. 상대적으로 긴 시간이 소요되는 I/O작업을 기다리지 않고 client의 요청과 응답만을 담당하기 때문에 더 적은 자원으로도 높은 성능을 기대할 수 있습니다. (사실 Single-Thread 방식은 Node.js의 특징이라기 보다는 Javascript의 특징이라고 보는게 맞습니다.)

 

+ 추가적으로 단 한개의 Thread만이 운용되기 때문에 기존 Multi-Thread 방식의 동기화 문제에서 완전히 자유롭습니다. 이로 인한 개발편의성의 이점도 얻을 수 있습니다.

 

 

 

 

그래서 Node.js가 Spring MVC보다 성능상 유리할까?

Node.js가 Spring MVC보다 성능상 우위에 있다라고 말하기 위해서 몇가지 전제사항이 있습니다.

 

1. 다중처리를 동시에 처리하도록 요구된다.

2. 많은 I/O 작업을 수행한다.

3. 단순한 CPU 작업만을 진행한다.

 

이같은 전제사항은 오늘날의 '전형적인' 웹 애플리케이션의 특징입니다. Node.js가 다른 웹프레임워크에 비해서 성능상 우위에 있다고 쉽게 거론되는 이유는 Node.js가 이러한 '전형적인' 웹 애플리케이션의 요구사항과 잘 어우러지기 때문입니다.

 

하지만 이러한 범주에서 벗어난 웹 애플리케이션이라면 반드시 Node.js가 정답이 될 수 없습니다. I/O작업이 많지 않고 강도높은 CPU 연산이 요구된다면 한개의 Thread를 사용하는 Node.js는 급격한 성능 저하가 야기됩니다.

 

Spring WebFlux의 등장

(Java 진영은 언제나 그래왔듯이 정답을 찾을 것입니다.)

 

Spring WebFlux는 Spring 5에서 도입되었습니다. Spring WebFlux는 Node.js와 유사하게 완전한 비동기-논블러킹 방식의 I/O 작업이 가능하고, 이를 제어하기 위한 Event Loop를 두었습니다. 다른 점이라면 Spring WebFlux는 Single-Thread 기반이 아닌 Multi-Thread 방식입니다. 다만 Spring MVC처럼 각 요청에 하나의 Thread가 대응 되지 않고 다수의 요청을 처리하는 구조입니다.

 

Java진영에서도 비동기-논블러킹 방식의 장점을 취하기 위해서 Node.js를 고려하지 않고 Spring 만으로도 개발이 가능하게 된 것입니다. 

반응형
반응형

1. 전체 프로세스 <로그인>

회원가입 - 이메일 - 이름 - 비밀번호 - 비밀번호확인 - 확인

 

 

2. RegisterPage 도 LoginPage 와 비슷한 맥락으로 만들어주기

 

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

function RegisterPage(props) {

    const dispatch = useDispatch();

    const [Email, setEmail] = useState("")
    const [Password, setPassword] = useState("")
    const [Name, setName] = 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) {
                props.history.push('/login');
            } 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>
                    회원가입
                </button>
            </form>
        </div>
    )
}

export default RegisterPage

RegisterPage.js

 

 

 

3. user_action에 registerUser 추가

 

import {
    LOGIN_USER,
    REGISTER_USER
} from './types';

export function registerUser(dataTosubmit){
    const request = axios.post('/api/users/register', dataTosubmit)
        .then(response => response.data)

    return {
        type: REGISTER_USER,
        payload: request
    }
}

 

 

 

4. types.js 에도 추가

 

export const REGISTER_USER = "register_user";

 

 

 

 

5. user_reducers 에 추가

 

import {
    LOGIN_USER, REGISTER_USER
} from '../_actions/types';

case REGISTER_USER:
            return { ...state, register: action.payload };

 

 

 

 

 

<로그아웃>

- 로그아웃 버튼 만들어주기

const onClickHandler = () => {
        axios.get('/api/users/logout')
        .then(response => {
            if(response.data.success){
                props.history.push('/login');
            } else {
                alert('로그아웃 하는 데 실패하였습니다.');
            }
        })
    }

LandingPage.js

 

+ props 넣어주기

반응형
반응형

< 전체 과정 >

로그인 -> 이메일 -> 비밀번호 -> 확인

 

 

1. 프로그램 실행

npm run dev

-> server와 client 모두 실행, client의 LandingPage가 로드된다.

 

 

2. LandingPage 디자인 수정

 

<div style={{
            display: 'flex', justifyContent: 'center', alignItems: 'center',
            width: '100%', height: '100vh'
}}>
     <h2>시작 페이지</h2>
</div>

 

 

- 페이지 새로고침 방지

event.preventDefault()

 

 

 

 

3. Redux를 이용한 LoginPage

 

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("")
    const onEmailHandler = (event) => {
        setEmail(event.currentTarget.value)
    } 
    const onPasswordHandler = (event) => {
        setPassword(event.currentTarget.value)
    }
    const onSubmitHandler = (event) => {
        event.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>
                    Login
                </button>
            </form>
        </div>
    )
}

export default LoginPage

LoginPage.js

 

 

 

 

4. user_reducer 만들어주기

 

import {
    LOGIN_USER
} from '../_actions/types';

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

user_reducer.js

 

 

-> 로그인 성공 시, loginSuccess가 뜨도록 해준다.

 

 

app.post('/api/users/login',(req, res) => {

  // 요청된 이메일은 데이터베이스에서 있는지 찾는다.
  User.findOne({ email: req.body.email }, (err, user) => {
    console.log(err)
    if(!user){
      return res.json({
        loginSuccess: false,
        message: "제공된 이메일에 해당하는 유저가 없습니다."
      })
    }
    // 요청된 이메일이 데이버테이스에 있다면, 비밀번호가 맞는 비번인지 확인한다.
    user.comparePassword(req.body.password, (err, isMatch) => {
      console.log(err)
      if(!isMatch) 
          return res.json({ loginSuccess: false, message: "비밀번호가 틀렸습니다."})

      // 비밀번호까지 맞다면 토큰을 생성하기
      user.generateToken((err, user) => {
        console.log(err)
        if(err) return res.status(400).send(err);

        // 토큰을 저장한다. 어디에?  쿠키, 로컬스토리지
        res.cookie("x_auth", user.token)  
        .status(200)
        .json({ loginSuccess: true, userId: user._id ,message: "비밀번호가 맞았습니다."})

      })
    })
  })
})

index.js(server)

 

 

-> 전에 index.js에서 설정해준 정보들이 나타난다.

 

 

 

5. reducers 안에 reducer를 관리하는 index.js 를 생성해준다.

 

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

const rootReducer = combineReducers({
    user
})

export default rootReducer;

index.js

 

-> reducer들은 여기에서 가져와서 사용하기로 한다.

 

 

 

 

6. user_action 만들기

 

import axios from 'axios';
import {
    LOGIN_USER
} from './types';
export function loginUser(dataTosubmit){
    const request = axios.post('/api/users/login', dataTosubmit)
        .then(response => response.data)

    return {
        type: LOGIN_USER,
        payload: request
    }
}

user_action.js

 

-> login action을 생성해준다.

 

 

 

 

6. 크롬에서 확인

 

Redux DevTools 라는 크롬 익스텐션을 설치해서

로그인 후 loginSuccess 가 뜨는지 확인한다.

 

반응형

'Programming > MERN' 카테고리의 다른 글

HTML 정리  (0) 2020.12.22
! 인증 체크하기 !  (0) 2020.11.10
Node.js 와 스프링의 차이 🤫  (0) 2020.11.10
🌺 회원가입 페이지 만들기 🌺  (0) 2020.11.09
CSS Framework / Redux 개념 및 설정  (0) 2020.11.02
반응형

< CSS Framework >

CSS Framework 종류 for React

1. Material UI -> 사용하기 어렵다.

2. React Bootstrap

3. Semantic UI

4. Ant Design 

5. Materialize

 

 

Ant Design을 사용할 것이다.

장점)

디자인이 깔끔하다.

Enterprise 환경에서도 잘 어울리는 디자인

쓰기가 용이하다.

 

단점)

용량이 매우 크다.

 

 

 

 

 

 

Ant Design 홈페이지에 가서 getting-started 따라한다.

 

ant.design/docs/react/introduce

 

Ant Design of React - Ant Design

Polyfills are needed for IE browsers. We recommend @babel/preset-env for it. You can set targets config if you are using umi. We recommend using npm or yarn to install, it not only makes development easier, but also allow you to take advantage of the rich

ant.design

 

 

 

비주얼 스튜디오 코드 Terminal에서

cd client
npm install antd --save

 

client/src/index.js에

import 'antd/dist/antd.css'; // or 'antd/dist/antd.less'

 

하면 설정 끝.

 

 

 

 

 

 

 

 

 

< Redux 이론 >

 

Redux란? 상태 관리 라이브러리

 

Prop vs State

 

1) Prop

: Properties의 약자

: 컴포넌트 간에 데이터를 주고받을 때 사용

: 부모 컴포넌트에서 자식 컴포넌트로만 보낼 수 있다.

: 부모 컴포넌트에게 받은 데이터를 자식 컴포넌트가 변경할 수 없다. 바꾸려면 다시 부모 컴포넌트에게 다른 값을 받아야한다.

 

 

2) State

: 부모, 자식 간의 그런 관계가 아니고, 컴포넌트 간의 데이터를 전달하는 방법이다.

: 따라서 받은 데이터를 변경할 수 있다.

: State에서 값을 변경하면 re-rendering 되는 효과가 있다.

: 예를 들어, 검색창에 글을 입력할 때 글이 변하는 것은 state를 이용한 것이다.

 

이러한 State를 관리하는 것이 Redux 이다.

 

 

 

 

 

 

 

모든 컴포넌트는 Comment를 가지고 관리하고 있다.

그리고 부모 컴포넌트는 자식 컴포넌트의 Comment도 관리하고 있다.

이 때, Redux가 자식 컴포넌트 Comment의 변화를 부모 컴포넌트에게 한번에 전달하는 역할을 한다.

아래 그립과 같이, Redux Store에 넣어놓고

 

 

 

 

 

 

 

 

 

 

< Redux 실전 >

 

1. 다운받아야 하는 dependencies

1) redux

2) redux - thunk

3) redux - promise

4) react - redux

 

3)과 4) 리덕스를 더 잘 사용할 수 있도록 도와주는 미들웨어이다.

 

npm install redux react-redux redux-promise redux-thunk --save

 

 

 

2. import

 

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

 

 

 

 

3. middleware

 

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

 

 

 

 

4. store

 

- 크롬 익스텐션 Redux DevTools 설치 후

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

 

 

 

 

5. _reducers 파일 밑에 index.js 파일 생성

 

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

const rootReducer = combineReducers({
    // user,
})

export default rootReducer;

 

 

 

 

 

 

 

 

반응형

+ Recent posts