HOC vs HOF

wooo·2023년 5월 1일
0

HOF

function aaa(){
	console.log("저는 aaa에요")

	return function bbb(){
		console.log("저는 bbb에요")
	}
}

위 코드의 결과는 콘솔에 "저는 aaa에요"만 출력이 되고 반환값으로 bbb함수가 있을 것이다.
"저는 bbb에요"를 출력하려면 bbb함수를 호출을 해주어야 콘솔에서 확인할 수 있다. bbb까지도 실행하는 방법은 aaa()()로 적어주면 된다.
이렇게 실행하면 콘솔에 aaa,bbb 모두 출력된 것을 볼 수 있다.

이를 조금 더 자세히 알아보면

function aaa(){
	const apple = 10

	return function bbb(){
		const banana = 5
		console.log(banana)
		console.log(apple)
	}
}

aaa()()

// 실행 결과
// 5
// 6

위의 함수는 파라미터를사용하여 조금 더 간경하게 바꿀 수 있다.

// 함수 선언식
function aaa(apple){

	return function bbb(banana){
		console.log(banana)
		console.log(apple)
	}
}

aaa(2)(3)

// 실행 결과
// 2 => aaa에 넣은 인자값
// 3 => bbb에 넣은 인자값

이렇게 각 변수를 함수의 파라미터로 넘기게 되면, 실행 시 넘겨준 인자값으로 콘솔이 출력된다.
bbbdp apple이 없음에도 불구하고 받아오는 이유는 클로저 때문이다.

위의 함수는 아래와 같이 화살표 함수로도 표현이 가능하다.

// 화살표 함수로 변경
const aaa = (apple)=>{
	return (banana)=>{
				console.log(apple)
				console.log(banana)
		}
}

aaa(2)(3)

이렇게 화살표 함수로 바꿔줄 수 있고, 여기서 중괄호와 리턴 사이에 아무것도 없다면 중괄호를 생략해서 적을 수 있다.
최종적으로는 아래와 같은 모양으로 된다.

// 중괄호 생략
const aaa = (apple)=>(banana)=>{
				console.log(apple)
				console.log(banana)
}

aaa(2)(3)

HOC

HOC는 Higher Order Component로 권한분기에서 배운 클로저로부터 확장된 개념이다.

HOC는 상위에 있는 컴포넌트로 다른 컴포넌트보다 먼저 실행되는 컴포넌트라고 생각하면 된다.

Aaa컴포넌트의 HOC(Bbb)({qqq:"철수"})를 보면 HOF에서 배웠던 함수를 리턴하는 함수의 호출방법과 비슷하다.
즉, Bbb부분에는 apple이 들어왔고, {qqq:"철수"} 부분에는 banana가 들어와있었다. 그리고 이를 참고하여 먼저 실행할 컴포넌트를 보면
HOC 함수의 매개변수(parameter) 부분에 component가 들어와 있다.
component 파라미터에 들어올 컴포넌트는 Bbb컴포넌트가 된다.
그리고 HOC함수에서 리턴되고 있는 함수를 보면, 리턴 함수의 매개변수로 props가 들어가 있고 해당 props에는 함수 호출 시 넣어준 인자값인 {qqq:"철수"}가 들어오게 된다.
밑으로 내려와 익명함수의 리턴값을 보면 내부에 컴포넌트가 없음에도 불구하고 컴포넌트를 리턴하고 있다. 이는 클로저로 외부의 컴포넌트를 가지고 올 수 있기 때문에 사용이 가능하다.


withAuth 만들어보기

위에서 배운 HOC 원리를 바탕으로 권한을 체크하는 HOC를 직접 만들 수 있다. 권한을 체크하는 컴포넌트는 어디든 사용될 수 있기 때문에 필요에 따라 따로 분리하여 관리해주면 편하다. (우리는 commons에 만들기로..)

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

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

	//loginCheckSuccess 파일에 있는 useEffect를 가지고 오시면 됩니다. 
	useEffect(()=>{
		if(!localStorage.getItem("accessToken")){
			alert("로그인을 먼저 해주세요")
			void router.push("/로그인 페이지")
		}
	},[])

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

🚀 HOC를 만들었는데 에러가 나요!
eslint 문제일 가능성이 큽니다!
eslint로 가서 rules에 “react/display-name”: “off” 이렇게 써주면 대부분의 문제가 해결이 된다.

🚀 이렇게 꺼도 Component와 props부분의 에러는 해결 되지 않아요!
→ Component와 props부분은 generic을 배워야 해결되는거니 지금은 잠시 넘어가기!

위와 같이 권한체크 HOC를 만들었다면 아래처럼 적용하고 싶은 페이지에 적용해주면 된다.

// loginSuccessPage -> withAuth 적용하기 

const LoginSuccessPage = ()=>{
	const {data} = useQuery(FETCH_USER_LOGGED_IN)

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

export default withAuth(LoginSuccessPage)

적용하는 방법은 위와같이 필요한 컴포넌트에 withAuth를 감싸서 export를 해주시면 된다.

이렇게 권한을 체크하는 Hoc를 만들어주고 필요한곳에 사용해주면 해당 컴포넌트가 실행되기 이전에 권한체크 컴포넌트가 먼저 실행된다.

0개의 댓글