[Next] Closure / HOC / HOF

0 0 0

권한 분기

로그인 이후에는 권한에 따라 화면과 기능을 나눠야 합니다. 가장 단순하게는 **로그인한 사람**과 **로그인하지 않은 사람**으로 나눕니다.

추가적으로 로그인에 등급을 매기면, 운영자로 로그인 한 사람, 판매자로 로그인 한 사람, 거래처 사장님으로 로그인 한 사람 등 다양하게 권한을 분리할 수 있습니다.

사전 지식

스택(Stack)

입구가 하나인 우물 형태의 데이터 구조입니다.

입구가 하나이기 때문에 가장 먼저 들어간 함수가 가장 나중에 나옵니다. 이를 First In Last Out, 줄여서 FILO라고 합니다.


큐(Queue)

양방향 출입이 가능한 파이프 형태의 데이터 구조입니다.

큐는 스택과 다르게 출입구가 나뉘어있어 가장 먼저 입력된 함수가 가장 먼저 빠져나갑니다. 이를 우리는 First In First Out이라고 합니다.

권한 분기는 클래스형 컴포넌트에서는 HOC 방식만 사용할 수 있고, 함수형 컴포넌트에서는 커스텀 훅(주로 사용)과 HOC를 모두 사용할 수 있습니다.



클로저와 스코프 체인

스코프 체인과 클로저 간단 정리

  • 클로저(closure): 함수와 그 함수를 둘러싼 렉시컬 환경(lexical environment)의 조합
  • 스코프 체인(scope chain): 변수를 찾을 때 현재 스코프에서 시작해 상위 스코프를 거쳐 전역 스코프까지 찾아 올라가는 과정

Scope Chain

Closure

bbb 함수 스코프 안에 apple 변수가 없기 때문에 상위 함수인 aaa의 스코프로 올라가 apple 변수를 찾습니다.

bbb가 apple을 찾을 수 있는 것은 bbb가 선언될 때의 환경(aaa의 스코프)을 기억하기 때문이며, 이것이 클로저입니다.



커링(Currying) 기법

커링(Currying)은 인자가 여러 개인 함수를, 인자를 하나씩 받는 함수들의 연쇄로 바꾸는 기법입니다.

커링을 사용하는 이유

  • 중복된 코드를 줄일 수 있습니다.
  • 필요한 기능을 적재적소에 조합해서 사용할 수 있습니다.
  • 실행 시점을 뒤로 미룰 수 있습니다.
function introduce(word) {
    return function (name) {
        console.log(`${word}, ${name} 입니다.`);
    };
}

const mySelf = introduce("안녕하세요"); 
mySelf("철수"); 	// 안녕하세요, 철수 입니다.
mySelf("영희");  // 안녕하세요, 영희 입니다.

HOF 작성법

HOF(Higher Order Function)

함수를 인자로 받거나 함수를 반환하는 함수를 HOF라고 하며, 여기서는 aaa가 HOF입니다.

// 1. 함수를 리턴하는 함수

function aaa() {
  const apple = 10;

  return function bbb() {
    const banana = 20;
    console.log(banana);
    console.log(apple);
  };
}
aaa();
// bbb() {
	const banana = 20;
    console.log(banana);
    console.log(apple);
}

(aaa())()
// 20 
// 10

() 생략가능
aaa()()
// 20
// 10

// 2. 함수를 리턴하는 함수 - 인자

function aaa(apple) {
  return function bbb(banana) {
    console.log(banana);
    console.log(apple);
  };
}
aaa(10)(20);
// 20
// 10


// 3. 함수를 리턴하는 함수 - 화살표함수

const aaa = (apple) => (banana) => {
  console.log(banana);
  console.log(apple);
};

aaa(10)(20);
// 20
// 10

좀 더 줄이기



HOC

HOC(Higher Order Component)는 위의 클로저와 HOF 개념을 컴포넌트로 확장한 것입니다.

HOC는 컴포넌트를 받아서 새 컴포넌트를 반환하며, 감싼 컴포넌트보다 먼저 실행된다고 생각하면 됩니다.

내부에 컴포넌트가 없음에도 불구하고 컴포넌트를 리턴하고 있습니다. 클로저 덕분에 외부에서 받은 컴포넌트를 사용할 수 있기 때문입니다.



WithAuth

권한을 확인하는 HOC 만들기

// src/components/commons/hoc/withAuth.tsx 파일

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

  // 로그인 체크
	useEffect(()=>{
		if(!localStorage.getItem("accessToken")){
			alert("로그인을 먼저 해주세요")
			void router.push("/로그인 페이지")
		}
	},[])

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

// /page/loginSuccessPage/index.tsx -> withAuth 적용하기 
const LoginSuccessPage = ()=>{
	const {data} = useQuery(FETCH_USER_LOGGED_IN)

	return <div>{data?.fetchUserLoggedIn.name}님 환영합니다.</div>
}

export default withAuth(LoginSuccessPage)

필요한 컴포넌트를 withAuth로 감싸서 export하면 됩니다. 이렇게 하면 해당 컴포넌트가 실행되기 전에 권한 확인이 먼저 실행됩니다.

댓글 0