[HOC] HOC를 이용해서 로그인 여부 확인하기

이주희·2022년 4월 13일
2

React ♥️ Next.js

목록 보기
33/48

연관 내용
[HOF]
[Closure]
[Local Storage]

먼저 실행되는 컴포넌트 :: HOC

사용되는 원리

👇🏻 컴포넌트를 함수 형태로 바꿔서 쓸 수 있다.

props는 단지 매개변수일 뿐이란 것을 알 수 있다. props 안 쓰고 asdfas 이따위로 써도 됨 ㅎㅎ

Aaa와 Bbb 사이에 컴포넌트를 추가해보자!

  • 먼저 실행 컴포넌트를 보면, 함수 안에서 함수를 리턴하고 있다.
    리턴하는 함수의 props를 리턴되는 컴포넌트에 전달해주고 있다.

  • Aaa를 실행시키면 Bbb 컴포넌트에 props가 전달되어서 리턴되는 것은 동일하고
    먼저 실행 컴포넌트의 로직들을 실행시킬 수 있게 된다.

중간에 추가한 먼저 실행 컴포넌트를 Higher Order Component라고 부른다.
Closure로부터 확장된 개념이다.

활용: 로그인 여부 확인이 필요한 페이지에 먼저 실행할 HOC를 추가해서 useEffect로 token을 체크해줄 수 있다.


더 간단하게 바꿔보자

Aaa

  • Bbb를 HOC로 감싸서 합쳐서 export한 것을 Aaa에서 import해서 쓰고 있다.
    👉🏻 HOC(Bbb)가 export default이기 때문에, Aaa에서 Bbb로만 적어도 HOC(Bbb)가 실행된다.

먼저 실행 컴포넌트

  • 👉🏻 중괄호와 리턴 사이에 아무것도 없으므로, 화살표 함수로 바꾸면 코드를 줄일 수 있다.
  • 리턴 전에 로직을 추가해야 하기 때문에 Component는 생략 노노
  • HOC는 보통 with를 붙여서 이름을 짓는 것이 관례이다.



HOC 만들기

함수명을 with~로 짓는 게 국룰🌟

1. withAuth 컴포넌트를 만든다.

import { useRouter } from "next/router";
import { useEffect } from "react";
// @ts-ignore
export const withAuth = (Component) => (props) => {
  const router = useRouter();

  /* 권한 분기 */
  useEffect(() => {
    if (!localStorage.getItem("accessToken")) {
      alert("로그인 후 이용이 가능합니다.");
      router.push("/23-04-login-check");
    }
  }, []);

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

1-1. TypeScript 제네릭 적용

// prettier-ignore
export const withAuth = (Component : ComponentType) => <P extends {}>(props:P) => {
  const router = useRouter();

  /* 권한 분기 */
  useEffect(() => {
    if (!localStorage.getItem("accessToken")) {
      alert("로그인 후 이용이 가능합니다.");
      router.push("/23-04-login-check");
    }
  }, []);

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

1-2. es lint 무시

컴포넌트의 이름이 없어서 에러가 난다.
Component.displayName~~ 해서 붙일 수 있지만 그러려면 화살표 함수를 다시 일반 함수로 바꿔야 한다ㅠㅠ
그냥 es-lint를 잠시 꺼두자..ㅎ
eslintrc.js

  rules: {
    "react/display-name": "off",
  },

2. HOC을 먼저 실행시킬 컴포넌트를 HOC으로 감싸서 export한다.

로그인이 필요한 페이지에 1에서 만든 withAuth로 감싸서 export default하면 해당 페이지가 실행되기 전에 withAuth가 먼저 실행된다.
요로케 👉🏻 export default withAuth(LoginSuccessPage);

import { gql, useQuery } from "@apollo/client";
import { withAuth } from "../../src/components/commons/hocs/withAuth";

const FETCH_USER_LOGGED_IN = gql`
  query fetchUserLoggedIn {
    fetchUserLoggedIn {
      email
      name
    }
  }
`;

function LoginSuccessPage() {
const { data } = useQuery(FETCH_USER_LOGGED_IN);

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

export default withAuth(LoginSuccessPage);
// withAuth가 먼저 실행된다.
// HOC의 매개변수인 Component에 LoginSuccessPage가 들어간다.
profile
🍓e-juhee.tistory.com 👈🏻 이사중

0개의 댓글