Next.JS는 SSR을 제대로 구현하기 위해 기본적으로 리액트 18버전에서 나온 서버 컴포넌트를 활용해 렌더링 하고 있다.
리액트의 새 기술인 서버 컴포넌트를 잘 모른다면 참고를 참고해달라.
리액트에서 정의하는 서버 및 클라이언트 컴포넌트 차이점은 아래와 같다.
타입 | 설명 | 주의사항 | 파일 네임 컨벤션 |
---|---|---|---|
서버 |
|
| Example.server.js |
클라이언트 |
|
| Example.client.js |
공유 |
|
| Example.js |
물론 서버 컴포넌트가 아예 SSR 렌더링과 동일하다 할 수 없고, 클라이언트 컴포넌트는 클라이언트만 렌더링된다라는 것도 아니다.
일단 이해를 돕기 위해 서버/클라이언트 컴포넌트는 SSR, CSR 렌더링 방식의 차이라고 서술했지만, 자세히 들여다보면 다르다는 얘기다.
이러한 배경이 있었기에 Page Router 때는 Next.JS의 고유 함수들을 써야 SSR 방식을 채택한 렌더링이 됐었다.
이제 App Router는 지시어가 없으면 기본적으로 SSR 렌더링 방식을 취하는 서버 컴포넌트로 구동된다.
PHP나 제이쿼리 등의 시절에는 SSR이 새로고침에 의한 블링크로 UX가 매끄럽지 못함, 브라우저 및 개인 컴퓨터 구동 환경 스펙이 부족함 등으로 한계가 명확했다.
그래서 CSR 방식인 차세대 웹 개발 라이브러리인 리액트, 뷰, 앵귤러들이 그 자리를 메꿨다.
페이지를 이동할 때마다 로딩이 없어 매끄러움, 상태 및 이벤트 등의 사용자 경험을 위한 함수 용이 등으로 각광을 받았지만, 요즘은 다양한 라이브러리들이 추가됨에 따라 번들 크기 증가 및 JS 초기 로딩 증가로 한계를 맞았다.
그래서 HTML을 생성하고, 미리 UI를 보여줄 수 있는 SSR 방식이 다시 각광을 받았다. 그런 방식으로 사용할 수 있게 만든 프레임워크 Next.JS, Nuxt.JS가 득세하고 있었다.
리액트는 이 변화에 탑승하기 위해 RSC, 리액트 서버 컴포넌트 개념을 만들어 18버전에 업데이트 했다.
서버 컴포넌트는 서버에서부터 복잡한 인터페이스를 구축하는 동시에 클라이언트로 전송되는 JavaScript의 양을 줄여, 초기 페이지 로드 속도를 높일 수 있다.
즉, SSR 방식을 채택하여 SSR의 장점 이용 및 CSR 한계를 타파하기 위해 나왔다.
Next.JS에서는 'use client'
지시어를 사용하지 않으면 자동으로 서버 컴포넌트로 감지하여 사용한다.
만약 use
로 시작하는 훅이나 이벤트가 포함돼있다면 'use client'
지시어를 사용하자.
그 외 다른 기준을 알고 싶다면 서버 상태 vs 클라이언트 상태를 봐보자. 상태 얘기긴 하지만 클라, 서버를 나누는 기준은 비슷하기에 위 글을 봐도 무방하다.
그리고 App Router는 app
폴더에서 폴더 + page.tsx
기준으로 URL 도메인을 나누고 라우팅이 이뤄진다.
또한 Next.JS의 라우팅 기능 및 generateStaticProps
나 Metadata
같은 애들은 서버 컴포넌트에서만 기능을 사용할 수 있다.
위에서 언급했듯이 서버 컴포넌트만 쓸 수 있는 기능이 있다. 그래서 /src/app
에서는 디렉토리를 짜는 파일만 만들고, UI나 use client
지시어를 사용할 만한 기능은 /component
나 /container
에 넣는 것이 좋다.
위 이미지는 내 실제 App Router 페이지인데, 동적 라우팅으로 SSG를 만들 때 쓰이는 generateStaticParams
, Metadata
이 있다.
저 두 기능들은 서버 컴포넌트, 즉, SSR 방식으로 렌더링해야지 적용할 수 있는 기능들이라 URL을 구성하는 파일만 저렇게 생성하고,
/containers
부터 'use client'
지시어를 사용하는 모습이다.
이런 식으로 해야 나중에 메타 데이터나 서버 컴포넌트로서 사용할 기능들을 적용하기 쉬워진다.
오늘 마침 딱.. ssr 관련 문제에 봉착했었는데 복기하기 좋은 타이밍이였네용 ㅎㅎ 잘 보고 갑니다!