개발 이야기/Next.js

Next.js - 데이터 가져오기 - 2

석구석구 2021. 8. 5. 02:24

Next.js를 사용하면 CSR과 SSR을 자유롭게 넘나들 수 있다.

Next.js에서는 데이터를 취급하는 방법이 몇 가지 있고, 이로 인해 렌더링 방식이 달라진다.

초기에 이 기능들을 정확하게 익히지 않으면, 계속 헷갈리게 된다. 차이점과 사용법을 분명하게 하고 시작하자.

 

웹 페이지는 크게 2가지로 나눌 수 있는데, 데이터가 필요 없는 페이지와 데이터가 필요한 페이지다.

1. 데이터가 필요 없는 정적 페이지를 Next.js가 취급하는 방법

index.tsx
profile.tsx

 

위와 같이 파일 2개를 간단하게 작성하고 npm run build -> npm run start 스크립트를 통해 빌드하고 로컬 서버를 열어 localhost:3000에 접속해보자.

  • 홈(/) 화면에서 프로필(/profile) 화면으로 이동해보자.
  • 반대로 프로필 화면에서 시작해서 홈 화면으로 이동해보자.

네트워크 탭을 열어 살펴보면 CSR 처리되는 것을 확인할 수 있다.

정적 페이지는 CSR로 처리된다.

 

2. 데이터가 필요한 페이지를 Next.js가 취급하는 방법

'블로그 포스팅', '회원 정보'와 같은 페이지들은, 서버에서 html을 내려주기 전에 데이터를 받아와야 하는 경우가 있다.

물론 CRA 같은 CSR만을 지원하는 프로젝트라면 고민 없이, 일단 스켈레톤 페이지를 렌더링 하고, axios 등을 이용해 데이터를 받아오고, 그 결과에 따라 화면을 재 렌더링 하게 될 것이다.

Next.js에서는 어떻게 취급될까. Next.js에서 데이터를 미리 가져오는 방법은 3가지 방법이 있다. 하나씩 정확하게 알아보자.

 

그런데 앞서 준비해야 할게 있다. Next.js와는 별도의 API 서버가 필요하다는 것이다.

localhost:4000번에 간단한 koa api 서버를 띄우자. 그리고 테스트용 라우터를 4개 만들자.

*Next.js의 api 폴더를 이용한 자체 api 서버가 아님을 유의하자.

koa api 서버의 라우터 파일

getStaticProps

  • pages/list.tsx 파일을 만들고 아래와 같이 작성하자.
  • npm run build 빌드하고 npm run start 명령으로 서버를 동작하자.
  • 홈(/) 화면에서 리스트(/list) 화면으로 이동하자.
  • 반대로 리스트 화면에서 시작해서 홈 화면으로도 이동해보자.

결과가 어떠한가? 재밌게도 빌드시점에 http://localhost:4000/posts로 요청을 하고, 배포 후에는 요청을 하지 않는다. 사용자가 몇 번이고 list 페이지에 접속해도 서버로 fetch 요청을 하지 않는다. 데이터를 static 하다고 여겨 단 한 번만 가져오는 것이다. 그것도 빌드 시점에! 일반적으로 아무리 static 한 데이터라 하더라도 이런 식의 동작은 곤란하다. 

이번에는 revalidate 옵션을 추가하고 다시 빌드하고 접속해보자. 어떠한가? 홈 화면이건 리스트 화면이건 페이지에 접속하는 시점에 api 서버로부터 데이터를 받아온다. 그리고 새로고침 전까지는 다시 데이터를 받아오지 않는다. 사용자가 새로고침을 하면 다시 api 서버로부터 데이터를 받아온다. 새로고침을 계속해보자. 매번 받아오는가? 그렇지도 않다. 5초 안에 새로고침을 했다면 해당 데이터는 받아오지 않는다. 예상보다 더 강력한 결과다.

 

notFound 옵션도 한번 살펴보자. 만약 true로 설정했다면 빌드 시점에 데이터가 없는 경우 404 페이지로 안내된다. 그리고 이후 데이터가 있더라도 해당 페이지는 언제나 404로 응답된다. 그렇다면 반대로 빌드 시점에는 존재하던 데이터가 어느 날 사라져 버리면 어떻게 될까? 데이터가 없는 동안에는 404 페이지를 응답할 테고 다시 데이터가 돌아오면 돌아온 데이터를 다시 캐시 한다.

빌드 시점에 데이터가 notFound라면 revalidate 옵션은 발동하지 않는다.

만약 해당 옵션이 false라면 어떨까? 빌드 시에 데이터를 받아오지 못했다면 빌드 에러가 나고, 잘 받아 왔다면 빌드에 성공한다. 그러던 어느 날 api 서버에서 데이터가 사라져 버리면 404 페이지로 전환대는 대신 컴포넌트를 그대로 렌더링 하게 된다. 그리고는 두 번 다시는 revalidate옵션이 발동하지 않는다.

 

getStaticProps는 데이터를 빌드 시점에 받아오고 캐시 한다.
개발자가 원한다면 캐시 데이터의 유효 시간을 설정할 수 있다.

getStaticPaths

  • pages/posts/[id].tsx 파일을 만들고 아래와 같이 작성하자.
  • npm run build 빌드하고 npm run start 명령으로 서버를 동작하자.
  • 홈(/) 화면에서 포스트(/posts/1) 화면으로 이동하자.
  • 주소창에 https://localhost:3000/posts/2 경로를 바로 입력하여 이동하자.
  • 주소창에 https://localhost:3000/posts/3 경로를 바로 입력하여 이동하자.

[id].tsx

개발을 하다 보면, 경로에 요청 정보가 포함되어 있는 경우가 있다. ex) https://localhost:3000/posts/1

이런 경우 [id].tsx와 같이 파일 이름에 괄호를 사용해, 동적 라우팅 파일을 작성하면 posts/1, posts/2... 와 같은 경로로 맵핑된다.

이처럼 경로가 데이터 fetch와 연관되어 있는 경우를 위해서 Next.js는 getStaticPaths 메서드를 지원한다. getStaticPaths는 빌드 타임에 동적 라우팅의 주소를 기억하게 된다. api 서버에서 posts 라우터를 통해 두 개의 posts 정보만을 제공했으므로 결과는 다음과 같다.

  • posts/1 정상 접속
  • posts/2 정상 접속
  • posts/3 404 응답

그런데 실제 운영 환경에서는 이래서는 곤란하다. 언젠가는 3번 포스트도 작성할 것이고 4, 5, 6번 포스트도 작성할 것이다.

fallback 옵션을 통해 이러한 상황에 대처할 수 있다.
(옵션 값을 false로 하면 빌드 타임에 맵핑되지 않은 경로는 항상 404 에러를 돌려주게 된다. 따라서 posts/3의 경로로 접속하면 실제로 3번 포스트를 작성했더라도 계속 404 페이지를 만나게 된다.) 

[id].tsx

fallback 옵션을 true로 설정하게 되면, 빌드 타임에 생성되지 않았던 경로라도 404 대신, getStaticProps 메서드를 통해 fetching을 하게 된다. 이후로는 응답을 캐시 하여 다시 요청하지 않는다. 놀랍지 않은가? 그런데 또 한 가지 재밌는 점은 컴포넌트를 랜더링 하고, fetching을 시도한다는 점이다. 아주 훌륭하다. pending 상황도 router의 isFallback 값으로, 시점을 제공해주므로 유용하게 이용할 수 있다.

getStaticPaths 메서드를 통해 동적 라우팅의 경로 유효성을 판단할 수 있고,
이후 생성되는 동적 라우팅 주소에도 유연하게 대처할 수 있다.

 


이처럼 Next.js는 Static 명칭이 들어간 두 개의 메서드로 정적 데이터를 캐시 하기 위한 놀라운 기능을 제공한다. 이제 마지막으로 SSR을 위한 메서드인 getServerSideProps를 알아보자.

 

 getServerSideProps

  • pages/list.tsx 파일의 내용을 아래와 같이 수정하자.
  • npm run build 빌드하고 npm run start 명령으로 서버를 동작하자.
  • 홈(/) 화면에서 리스트(/list) 화면으로 이동하자.

어떠한가? 페이지에 접속할 때마다 계속 요청을 한다. nextjs 서버에서 api 서버로 요청을 하고 데이터를 받아온 이후, 클라이언트에 최종 응답을 내려주기 때문에 posts를 가져오는데 3초가 걸린다면 사용자는 3초를 기다리게 될 것이다.

페이지 이동을 통해, 해당 라우터에 접근 할 때마다 매번 요청을 하게 된다. 페이지를 완성하기 전에 요청해서 초기 렌더링도 늦어지고, 페이지마다 계속 호출되는데 단점만 있는거 아냐? 라고 생각하기 쉽지만 보안이 필요한 api 호출이나 인증과정이 전처리로 요구된다면 유용하게 사용할 수 있다. 물론 사용자에게 초기 렌더링을 늦추더라도 필수적인 데이터가 있다면 이용할 수도 있겠지만 개인적으로 그런건 첫 렌더링 이후로 미루는게 낫다고 생각한다.

 

getServerSideProps는 서버 to 서버 구간의 보안이나 인증 등이 요구되는,
전처리 호출이 필요한 경우 사용하자. 

 

이상 nextjs에서 제공하는 3가지 데이터 호출 시점을 살펴봤다. 다음 시간에는 번들링 옵션에 대해 알아보자.

'개발 이야기 > Next.js' 카테고리의 다른 글

NextJS + Meterial UI  (0) 2021.11.26
Next.js - Assets 경로와 런타임 변수 - 4  (0) 2021.09.07
Next.js - 서버 분리 - 3  (0) 2021.09.07
Next.js - 시작 - 1  (0) 2021.08.01