Next.js  HOC 안에 hook 로직 넣기
공부내용 공유하기

Next.js HOC 안에 hook 로직 넣기

진행하고 있는 프로젝트의 오픈 준비로 한동안 포스팅을 하지 못하고 있었다.

 

1차 오픈을 하고 어느정도의 여유를 찾은 만큼, 틈틈이 포스팅을 다시 해보려고 한다.

 

오늘은 프로젝트 마무리 단계에서 SEO를 위한 각종 분석툴과 GA, 메타테그를 붙이면서

프로젝트 전체에 적용되어야 할 HOC를 만드는 과정에서 배운 내용을 적어보려고 한다.

 

먼저 HOC란 High Order Component. 즉 고차 컴포넌트이다.

 

고차 컴포넌트 – React

A JavaScript library for building user interfaces

ko.reactjs.org

설명에 잘 나와있듯이, 컴포넌트를 인자로 받아 새 컴포넌트를 반환하는 함수이다.

 

일반적으로 컴포넌트는 props를 받아 UI를 렌더링하지만, HOC는 컴포넌트를 받아 일련의 로직, 혹은 UI를 추가/수정 후 다시 반환하는 함수라고 보면 되겠다.

즉, HOC는 그 자체로 사용될 수 없으며, 항상 인자로 컴포넌트를 받아야 한다.

 

나같은 경우는 Next.js에서 HOC를 Private한 페이지에 걸어놓는 용도로 이미 사용하고 있었다.

 

유저 세션 조회는 앞단에서 따로 하고, 유저 정보는 redux store에 이미 존재하는 상황에서 유저 확인 후 마이페이지등에 접근할지 확인하는 HOC이다.

 

나 같은 경우는 리덕스 안에 유저세션을 넣어두는 로직이 선행되어 있어서, 리덕스 안에 저장된 유저 상태를 통해 구분했다.

 

// * import ~~~ *//

const MY_PAGE_URL = [
  ROUTE_URL.MY_PAGE_MAIN,
  ROUTE_URL.MY_REVIEW,
  //...
];

const isInArray = (arr: any[], target: any) => {
  return arr.some((value) => value === target);
};

const isPrivatePage = (url: string) => {
  return isInArray(MY_PAGE_URL, url);
};

const withMyPage = (WrappedComponent: any) => {
  const hocComponent = ({ ...props }) => (
    <>
      <Head>
        <title>마이페이지</title>
      </Head>
      <WrappedComponent {...props} />
    </>
  );

  hocComponent.getInitialProps = async (ctx: any) => {
    const { auth } = ctx.store.getState();
    const { user } = auth;

    if (!user) {
      // ? 유저정보 누락시 - 서버;
      if (ctx.req) {
        ctx.store.dispatch(setModal({ modalState: "login" }));
        ctx.store.dispatch(setRedirectUrl(ctx.asPath));
      }
      // ? 유저정보 누락시 - 클라이언트
      if (!ctx.req) {
        await Router.push(ROUTE_URL.MAIN);
        Alert("로그인이 필요한 서비스입니다.");
        ctx.store.dispatch(setModal({ modalState: "login" }));
        ctx.store.dispatch(setRedirectUrl(ctx.pathname));
      }
    }
    
    if (WrappedComponent.getInitialProps) {
      const wrappedProps = await WrappedComponent.getInitialProps(ctx);
      return wrappedProps;
    }
  };

  return hocComponent;
};

export default withMyPage;

 

동일한 구조에서 hook 로직을 넣어주고 싶다면 hocComponent 내부에서 호출하면 된다.

 

참고로 hocCoponent의 getInitialProps는 커스텀할 로직이 없더라도 명시적으로 꼭 실행해줘야 한다.

 

그러지 않으면 자식 컴포넌트의 initalProps가 실행될 기회가 날아가서 hoc로 감싼 컴포넌트의 initialProps는 실행이 안 되기 때문...

 

 

const withSEO = (WrappedComponent: any) => {
  const hocComponent = ({ ...props }: any) => {
    const isNotServer = typeof window !== "undefined";

    const isProduction = process.env.NEXT_PUBLIC_ENV === "pro";

    useEffect(() => {
      if (isNotServer) {
       if(isProduction){
       // TODO 마케팅 로직. GA등
      }
    }, []);

    const naverWebMasterCode = isProduction ? NAVER_PRO : NAVER_DEV;

    const ogImageUrl = isProduction ? URL_PRO : URL_DEV;

    return (
      <>
        <Head>
          <script async src={sourceUrl} />
          <title>타이틀</title>
          <meta property="og:title" content="타이틀" />
          <meta
            property="og:description"
            content="설명"
          />
          <meta
            property="og:image"
            content={`${ogImageUrl}`}
          />
          <meta name="naver-site-verification" content={naverWebMasterCode} />
        </Head>
        <WrappedComponent {...props} />
      </>
    );
  };

  hocComponent.getInitialProps = async (context: any) => {
    if (WrappedComponent.getInitialProps) {
      const wrappedProps = await WrappedComponent.getInitialProps(context);
      return wrappedProps;
    }
  };

  return hocComponent;
};
export default withSEO;

 

Next.js HOC with Hooks는 이걸로 끝~

 

---

 

번외로 next conf가 곧 열린다고 하니 관심있는 분들은 아래에서 확인해보시길..

https://nextjs.org/conf