권한분기

hyeseon han·2021년 10월 9일
0

클로저 함수(Closure function)

function 안에서 function으로 return 하는 함수

function aaa(){
	const myAaa = "111"
    
    return function bbb(){
		const myBbb = "222"
    }
}

myAaa: 매개변수
지역함수: 함수 내부에서 선언된 변수

aaa()
//실행결과
f bbb(){
	const myBbb = "222"
}
(aaa())()
//실행결과
111

내부에 있는 함수(bbb)가 외부에 있는 함수(aaa)에 있는 지역변수에 접근할 수있다
=> 이 개념을 사용해서 HOC를 만든다


권한분기

  • 사용자 서버 안에서 로그인한 유저 / 로그인 안한 유저 로 권한을 구분

  • 권한을 구분하는 방법으로 useEffect에서 accessToken이 없으면 "/login" 화면으로 페이지를 이동킨다.

export default function QuizLoginSuccessPage() {
  const router = useRouter();
  const { data } = useQuery(FETCH_USER_LOGGED_IN);
  const { userInfo, setUserInfo, accessToken } = useContext(GlobalContext);
  useEffect(() => {
    if (userInfo.email) return;
    if (!accessToken) {
      router.push("/quiz/login");
      alert("로그인을 먼저 해주세요");
    }
    setUserInfo({
      name: data?.fetchUserLoggedIn.name,
      email: data?.fetchUserLoggedIn.email,
      picture: data?.fetchUserLoggedIn.picture,
    });
  }, []);
  return (
    <>
       <div>로그인에 성공하셨습니다!</div>
      {data?.fetchUserLoggedIn.name}님 환영합니다~
    </>
  );
}

권한분기를 하려면 로그인 권한을 부여하려는 페이지에 모두 위의 로직을 입력해야하는 번거로움이 있다.

따라서, 이 문제를 해결하기 위해서 HOC를 사용한다.

HOC(Higher Order Component)

  • 특정 컴포넌트를 실행하기 전에 상위 컴포넌트를 먼저 실행시켜주는 방식이다.
  • JavaScript의 클로저 함수를 이용한다.
  • HOC를 하나 만들어서 로그인이 필요한 컴포넌트 앞에 HOC만 붙여주면 간단하게 권한처리를 완료한다.
  • 다른 컴포넌트와 함께 실행되는 고차 컴포넌트이므로 이름 앞에 with 를 붙여준다.
  • 예) withAuth, withApollo
// 클로저 개념
// 외부 함수에서 받은 Component라는 변수는 내부 함수에서 사용

const withAuth = (Component) => (props) => {
  const router = useRouter();
  const { accessToken } = useContext(GlobalContext);

  // 토큰체크
  useEffect(() => {
    if (!accessToken) router.push("/login");
  }, []);

  if (!accessToken) return <></>;
  return <Component {...props} />;
};

export default withAuth;
const UserPage = (props) => {
  return <div>회원 페이지입니다.</div>;
};

export default withAuth(UserPage);

HOC 장점

  1. event.target.id 를 사용하지 않아 코드가 간략해진다.
  2. material-ui, ant-design 등의 컴포넌트를 이용하면 id 값이 날라가는 현상을 막을 수 있다.
  3. id는 전체 태그에서 고유해야하기 때문에, id가 남용되면 대규모 서비스에서 문제가 야기될 수 있지만 이를 방지할 수 있다.(id 중복..)
// 기존 방법

export default function Aaa(){

	const onClickButton = (event) => {
		console.log(event.target.id)
	}

  return <button id={123} onClick={onClickButton}>클릭</button>
	
}
// HOF 적용

export default function Bbb(){

	const onClickButton = (id) => (event) => {
		console.log(id)
	}

 return <button onClick={onClickButton(123)}>클릭</button>
	
}

HOF(Higher Order Function)

  • HOC와 비슷하지만 HOC는 Component 형태, HOF는 Function 형태의 차이가 있다.

    Component 형태: JSX(React HTML)return 한다

    Function 형태: JSXreturn 안한다.


실습

  1. 공통컴포넌트 폴더에 파일 withAuth 생성
import { useRouter } from "next/router";
import { useEffect } from "react";

export const withAuth = (Component) => (props) => {
  const router = useRouter();

  useEffect(() => {
    const accessTokenItem = window.localStorage.getItem("accessToken");
    console.log("withAuth", accessTokenItem);
    if (!accessTokenItem) {
      alert("로그인을 먼저 해주세요");
      router.push("./login");
    }
  }, []);

  return <Component {...props} />;
};

2. 권한을 구분하기 위해서 권한을 부여하려는 페이지 앞에 `withAuth`로 감싼다.
import { gql, useQuery } from "@apollo/client";
import { withAuth } from "../../../src/components/commons/hocs/withAuth";

const LogInfoPage = () => {
  const { data } = useQuery(FETCH_USER_LOGGED_IN);

  return <div>로그인한 유저 정보 페이지</div>
};

export default withAuth(LogInfoPage);

withAuth가 실행되고 LogInfoPage가 실행되어 로그인 상태인 유저만 페이지에 들어갈 수 있다.

0개의 댓글