UseEffect
내부에서 useRouter
의 query
object
의 값을 사용하는 경우가 많았습니다. 예를 들어서, query
obejct
의 값을 이용해서 mount
시에 api 호출을 해야하는 경우입니다. 이러한 상황에서 query
object
에 원하는 값이 들어오지 않고 undefined
가 담겨서 오는 문제가 발생했는데 해결 방법은 알고 있지만, 왜 이렇게 동작하는지에 대해서 deep dive하고 싶어서 조사를 하게 되었습니다.
useRouter
에서 제공해주는 isReady
를 사용
// url - localhost:3000/fe?genius=eunchong
useEffect(() => {
if(isReady) {
console.log(query.genius) // eunchong
}
, [isReady])
isReady
: boolean
- router fields가 client-side에 업데이트되어 사용할 준비가 되었는지에 대한 여부.
Next.js는 blocking data requirements가 없는 경우 페이지가 static(prerendered가 가능)인지 자동으로 결정합니다. This determination is made by the absence of getServerSideProps
and getInitialProps
in the page.
blocking data requirements
"Blocking data requirements"는 Next.js에서 페이지가 미리 렌더링되기 전에 가져와야 하는 데이터를 가리키는 개념입니다. 이 데이터가 가져와지는 동안 브라우저가 기다려야 하므로 "blocking"이라는 용어가 사용됩니다. 이러한 데이터 요구사항이 없는 경우 페이지는 정적으로(pre-rendered) 생성될 수 있습니다.
결론적으로, Next.js에서getServerSideProps
나getInitialProps
를 사용하여 server-side에서 데이터를 fetch하는 경우 발생합니다.
만약 page에서 getServerSideProps
or getInitialProps
를 사용하고 있다면, Next.js는 요청에 따라 페이지를 요청 시 렌더링하도록 전환합니다. (서버 사이드 렌더링을 의미)
만약 위 케이스가 아닌 경우에는 Next.js는 정적으로 생성된 html을 pre-redering 함으로써 statically optimize할 것입니다.
pre-rendering하는 동안에는 router's query
object가 비어 있습니다. 이는 pre-rendering 단계에서 query
정보를 제공할 수 없기 때문입니다. 하지만 하이드레이션(hydration) 이후에 Next.js는 애플리케이션을 업데이트하여 query
object에 route parameters를 제공합니다.
hydration은 클라이언트 측에서 서버로부터 전달된 HTML 및 자바스크립트 코드를 받아 렌더링된 페이지를 동적으로 만드는 과정을 말합니다. pre-rendring된 페이지는 초기에는
query
정보를 가지고 있지 않기 때문에query
object가 비어 있습니다. 하지만 클라이언트에서 페이지가 로드되고 자바스크립트가 실행될 때, Next.js는query
정보를 포함한 URL을 읽어와서 페이지를 업데이트합니다. 이렇게 함으로써 route parameter나query
parameter 같은 정보를 사용하여 페이지를 동적으로 조작하거나 업데이트할 수 있습니다.
next build
will emit .html
files for statically optimized pages. For example, the result for the page pages/about.js
would be:
.next/server/pages/about.html
And if you add getServerSideProps
to the page, it will then be JavaScript, like so:
.next/server/pages/about.js
getServerSideProps
or getInitialProps
를 사용하지 않는 정적으로 pre-rendering(SSG)된 페이지는 hydration이 완료되기 이전에는 query
에 정보가 담겨서 오지 않습니다. pre-rendering 단계에서는 query
정보를 사용할 수 없기 때문입니다.
URL : http://localhost:3000/upa/use-case/7
getServerSideProps
or getInitialProps
사용하지 않은 페이지useEffect(() => {
console.log('test query', query);
}, [query]);
{}
{useCaseId: '7'}
getServerSideProps
or getInitialProps
를 사용하지 않은 페이지useEffect(() => {
console.log('test query', query);
}, [query]);
export const getServerSideProps = () => {
//
}
{useCaseId: '7'}
next.js/packages/next/src/shared/lib/router/router.ts
export default class Router implements BaseRouter {
this.isReady = !!(
self.__NEXT_DATA__.gssp || // getServerSideProps
self.__NEXT_DATA__.gip || // getInitailProps
(self.__NEXT_DATA__.appGip && !self.__NEXT_DATA__.gsp) ||
(!autoExportDynamic &&
!self.location.search &&
!process.env.__NEXT_HAS_REWRITES)
)
...
}
__NEXT_DATA__
는 페이지에 관한 정보를 가지고 있다.
gssp
는 getServerSideProps gip
는 getInitailProps라는 의미이고 사용 여부를 나타낸다.
Router
가 생성될 때 isReady
의 초기값은 gssp
or gip
가 사용 여부에 따라 하나라도 사용을 했으면 true
로 결정된다.
물론, 다른 값도 검사를 하는데 다른 값들의 의미는 아직 파악하지 못했다. 이 부분은 추후에 알아보고 추가하기로..