성장과정(dev)/Frontend(feat. Vue, Next.js)
[react] HOC를 사용한 페이지별 접근인증
lowellSunny
2020. 11. 16. 11:42
* HOC(higher-order component) ?
> 특징 : 다른 컴포넌트를 받아 새로운 컴포넌트를 return하는 function
> Auth라는 컴포넌트(HOC) 내에 다른 컴포넌트들을 삽입 가능
const EnhancedComponent = higherOrderComponent ( WrapperdComponent );
* HOC 적용방법
1. front 폴더 아래 hoc 폴더 auth.js 생성
import react, {useEffect} from 'react';
import Axios from "axios";
import {useDispatch} from "react-redux";
import { auth } from '../_actions/user_action';
/**
*
* @param specificComponent - 감쌀 컴포넌트
* @param option - null: 아무나 출인이 가능한 페이지, true: 로그인한 유저만 출입가능, false: 로그인한 유저는 접속불가능항 페이지
* @param adminRoute - 관리자만 접속할 수 있도록 하는 옵션
* @returns {*}
*/
export default function( SpecificComponent, option, adminRoute = null ) {
function AuthenticationCheck( props ) {
const dispatch = useDispatch();
useEffect( () => {
dispatch( auth() ).then( response => {
if( !response.payload.isAuth ) {
if( option ) {
props.history.push( '/login' )
}
}
else {
if( adminRoute && !response.payload.isAdmin ) {
props.history.push( '/' )
}
else {
props.history.push( '/' )
}
}
} )
//Axios.get( "/api/users/auth")
}, [] )
return (
<SpecificComponent/>
)
}
return AuthenticationCheck
}
2. action에 auth 추가 (파일명 user_action.js)
//get 메소드는 body 부분이 필요하지 않음
export function auth() {
const request = axios.get('/api/user/auth' )
.then( response => response.data )
// return을 시켜 Reducer로 보내줌.
return {
type: AUTH_USER,
payload: request
}
}
3. action에서 호출할 user_reducer 추가
export default function( state = {}, action ) {
// 정의 된 타입이 많아질 것이기 때문에 switch문을 사용
switch( action.type ) {
case LOGIN_USER :
return {...state, loginSuccess: action.payload }
break;
case REGISTER_USER :
return {...state, register: action.payload }
break;
case AUTH_USER :
return {...state, userData: action.payload }
break;
default:
return state;
}
}
4. App.js 에 생성한 auth import 한 후 컴포넌트들을 Auth 로 감싸준다.
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
import LandingPage from "./components/views/LandingPage/LandingPage";
import LoginPage from "./components/views/LoginPage/LoginPage";
import RegisterPage from "./components/views/RegisterPage/RegisterPage";
import Auth from './hoc/auth';
function App() {
return (
<Router>
<div>
<hr />
{/*
A <Switch> looks through all its children <Route>
elements and renders the first one whose path
matches the current URL. Use a <Switch> any time
you have multiple routes, but you want only one
of them to render at a time
*/}
<Switch>
<Route exact path="/" component={Auth( LandingPage, null, true)}/>
<Route exact path="/login" component={Auth(LoginPage, false)}/>
<Route exact path="/register" component={Auth(RegisterPage, false)}/>
</Switch>
</div>
</Router>
);
}
export default App;
* props.history.push( "페이지url" )
가리키는 페이지로 넘어가게 하기 위해서 props.history.push 해당 이벤트를 사용하는데
이것을 사용하려면 필요한 라이브러리가 있다.
import {withRouter} from 'react-router-dom';
여기서 withRouter는 주로 history에 접근하여 컴포넌트에서 라우터를 조작하는 데 사용
해당 라이브러리를 사용하지 않으면 아래와 같은 에러가 발생한다.
LoginPage.js:36 Uncaught (in promise) TypeError: Cannot read property 'push' of undefined

==========================================
※추가정보
해당 코드에서 세미콜론을 붙이고 안붙이고의 차이는 딱히 없다. 웬만하면 끝에 세미콜론을 붙여주는 것 추천