Next.js

[Next.js] router.query 사용 시 'undefined' 오류 해결

킹우현 2023. 6. 15. 15:28

이번 SW 캡스톤디자인 프로젝트에서 대회 페이지를 제작하던 중 대회 id를 query로 받기 위해 useRouter Hook을 사용하다가 router.query 값이 'undefined'로 들어오는 오류가 발생했다.
 
이전 페이지에서 쿼리 값을 전달해줬을 경우에는 문제가 발생하지 않았는데, 새로운 경로로 접속하거나 뒤로가기를 했을 경우에 이러한 오류가 발생했었다.
 
이는 Next.js의 정적 파일 최적화(Automatic Static Optimization)로 인해 라우트 매개 변수가 제공되지 않기 때문이라고 한다.
 

정적 파일 최적화(Automatic Static Optimization)란 ?

Next.js는 페이지가 데이터 요구사항이 없으면(즉, 서버에서 데이터를 가져올 필요가 없으면) 정적(사전에 렌더링 가능한) 페이지인 것으로 자동으로 간주한다.
 
이 결정은 페이지에서 getServerSideProps와 getInitialProps가 없는 경우에 이루어지는데, 이 기능을 통해 Next.js는 서버에서 렌더링된 페이지와 정적으로 생성된 페이지를 모두 포함하는 하이브리드 애플리케이션을 만들 수 있다.
 
이 기능의 주요 이점 중 하나는 최적화된 페이지가 서버 측 계산이 필요하지 않으며, 여러 CDN 위치에서 즉시 스트리밍될 수 있기 때문에 사용자에게 매우 빠른 로딩 경험을 제공한다는 것이다.
 

작동 방식

getServerSideProps 또는 getInitialProps가 페이지에 있는 경우, Next.js는 페이지를 요청별로 필요할 때 렌더링하기 위해 전환한다(즉, 서버 사이드 렌더링).
 
만약 위와 같은 경우가 아니라면, Next.js는 페이지를 정적 HTML로 사전 렌더링하여 자동으로 정적으로 최적화(statically optimize)한다.
 
사전 렌더링 중에는 라우터의 쿼리 객체가 비어 있으며, 이 단계에서는 쿼리 정보를 제공할 수 없다. ⭐️
하이드레이션 후에 Next.js는 쿼리 객체에 라우트 매개변수를 제공하기 위해 애플리케이션을 업데이트한다.
 
쿼리가 하이드레이션 후 업데이트되어 다시 렌더링이 트리거되는 경우는 다음과 같다.

  1. 페이지가 동적 경로일 경우
  2. 페이지의 URL에 쿼리 값이 있을 경우

쿼리가 Hydration 후 완전히 업데이트되어 사용할 수 있는지 여부를 구분하려면 next/router의 isReady 필드를 활용할 수 있다.
 

해결 방법

isReady 사용 예시
  useEffect(() => {
    if (router.isReady) {
      const { id } = router.query;
      if (!id) return;
      getContestDetail(parseInt(id));
    }
  }, [router.isReady]);

결론적으로, 페이지가 정적 HTML로 사전 렌더링(Pre-rendering)되고 있을 때는 라우터의 쿼리 객체가 비어있기 때문에 이 시점에 query 값을 이용해서 REST API를 사용하게 되면 쿼리 값이 undefined 로 들어가게 되어 오류가 발생하게 된다. ⭐️⭐️⭐️⭐️⭐️
 
따라서 라우터 필드가 클라이언트 측에서 업데이트되어 사용할 준비가 되었는지 확인하기 위해 router.isReady 를 사용하여 해결하였다.
 
이때 useEffect Hook를 사용하여 isReady 값을 감시하도록 하고, 라우터 필드가 사용할 준비가 되었을 때 대회 id 값을 저장하는 방식으로 해결할 수 있었다.