Next.js의 SSG fallback
Next.js의 SSG에서 지원하는 fallback 기능에 대해 알아보자구요 🥸
서론
Next.js 9.3 버전에 데이터 패칭 방식과 데이터 렌더링 방식이 변경되었다.
지금 보고 있는 이 블로그를 만들면서, 데이터 패칭 방식을 고민하고 여러 번 변경했었다. (이것도 나중에 글을 작성할 것이긴 한데, 이 블로그는 노션을 기반으로 한다.)
getServerSideProps
를 사용하다가 getStaticProps
으로 변경하면서, getStaticPaths
에 있는 fallback
기능에 대해 알아보기로 했다.
getStaticPaths
는 fallback
옵션을 무조건 포함하여야 한다.
fallback 옵션
기본적으로 fallback은 데이터가 없을 때, 즉 404일 때 할 행동을 고르는 것이다.
원래라면 그냥 데이터가 없는 것이겠으나, 빌드 시 미리 데이터를 패칭하여 생성해놓는 Next.js는 빌드 이후에도 데이터를 생성할 수 있게 지원한다.
`fallback: false`
데이터가 없으면 404를 표시한다.
즉, 아무 것도 하지 않는다. API에서 새로운 데이터를 받아서 갱신하고 싶다면 새로 페이지를 빌드하여야 한다.
`fallback: true`
데이터가 없으면 비동기적으로 데이터를 받는다.
- 기존에
getStaticPaths
에서 지정한 페이지들은 빌드 시에 Pre-render 해놓았으므로 표시한다.
- 데이터가 없다면(404), Next.js는 서버에서 데이터를 Fetch해본다. (
isFallback
:true
) - Fetch 데이터가 존재한다면, Next.js는 HTML과 JSON을 정적으로 생성한다. 이 땐
getStaticProps
가 다시 실행되는 것과 마찬가지다. (isFallback
:false
) - 데이터가 없다면 404를 표시한다. (
isFallback
:false
)
과정 옆에 isFallback
을 표시한 이유는, 이 과정이 서버에서 백그라운드로 (비동기적으로) 진행되기 때문이다. 우리가 isFallback
을 따로 처리해주지 않는다면, 서버 단에서 넘어온 Props 데이터는 undefined
로 표시될 것이다.
데이터가 undefined
라면 당연히 표시하는 데이터는 오류가 발생할 것이다... (그리고 이것이 내가 이 글을 쓰는 주 된 이
`fallback: 'blocking'`
데이터가 없으면 동기적으로 데이터를 받는다.
이 옵션의 경우에는 true
일 때와 비슷하게 동작하나, 모든 fallback 작업이 끝난 후에 페이지를 로딩한다는 점이 있다.
따로 isFallback
을 받아 처리하는 등의 작업이 필요 없기에 개발자는 편하지만, 그만큼 페이지 로딩 속도를 늦어진다. UX적으로 생각해보자면 당연히 비동기적인 작업이 권장될 것이다.
router.isFallback
그럼 fallback
의 상태를 받을 수 있는 옵션도 살펴보자. (공식 Fallback Pages 링크도 참고)
// 소스 예제의 출처는 Next.js 공식 문서입니다.// Route: /posts/{id}function Post({ post }) { const router = useRouter()
// 아직 페이지가 생성되지 않은 경우, 표시됩니다. // getStaticProps()가 완료될 때까지 표시됩니다. if (router.isFallback) { return <div>Loading...</div> }
// 생략...}
// 이 함수는 빌드 시에 실행됩니다.export async function getStaticPaths() { return { // 빌드 시에는 `/posts/1`과 `/posts/2`만 생성됩니다. paths: [{ params: { id: '1' } }, { params: { id: '2' } }], // 추가적인 페이지 생성(fallback) 을 켭니다. // 예를 들자면: `/posts/3` 같은? fallback: true, }}
// 이 함수도 빌드 시에 실행됩니다.export async function getStaticProps({ params }) { // params은 post의 `id`를 포함합니다. // 라우트가 /posts/1이라면, params.id는 1이 됩니다. const res = await fetch(`https://.../posts/${params.id}`) const post = await res.json()
// 받은 post 데이터를 props로 넘깁니다. return { props: { post }, // 이 부분은 추후 다른 글에서 다룰, revalidate 기능입니다. // 리퀘스트가 온 이후, 데이터를 재생성(re-generate)합니다. revalidate: 1, }}
주의 할 점!
fallback
은 없는 페이지를 생성할 뿐, 데이터를 다시 받아오는 기능은 아니다.- 이 기능은 Next.js에서 제공하는 ISR을 참고.
- ISR도
fallback
과 함께 부드럽게 동작한다.
- 위에서도 언급했지만,
fallback: true
라면 isFallback을 무조건 처리해주어야 한다. 안한다면 Pre-render 과정에서 바로 오류난다.
Error occurred prerendering page "/post/[slug]". Read more: https://err.sh/next.js/prerender-errorTypeError: Cannot read property 'title' of undefined
- Static HTML Export를 사용하는 경우, 당연하게도 서버리스 함수를 사용할 수 없기 때문에
fallback
은 무시된다. - 여담이나 같은 이유로 ISR 같은 서버리스 함수가 필요한 다른 기능들도 사용할 수 없다.