nextjs app router, 정말 알고 사용하시나요?

우빈·2024년 8월 9일
32
post-thumbnail

몇 가지 질문을 드리겠습니다.

  • app router가 출시된 이유는 무엇인가요?
  • app router에서 기본적으로 server component를 제공하는 이유는 무엇인가요?
  • app router에서는 SSG와 SSR을 어떻게 사용할 수 있나요?

해당 글은 위의 질문들을 중심으로 서술됩니다.

app router가 출시된 이유

2023년 5월, 평화롭게 pages router로 프로젝트를 개발하던 저는
새로운 라우팅 방식이 나왔다는 소식을 듣고 절망했습니다.
좋은 소식이지만 그땐 또 공부해야되는게 너무 싫었거든용...
(Next.js를 입문한지 3개월 째 되던 날이었습니다..)

그렇다면 Next.js가 app router를 출시한 이유는 무엇일까요?
저는...

Next.js를 오직 클라이언트 사이드가 아닌 풀스택 프레임워크로 발전시키기 위해서

라고 생각했습니다.
기존에는 'React의 프레임워크'로, 클라이언트 단에서 처리하기 복잡하거나 번거로운 일을
처리해주는 프레임워크로 자리잡았습니다.

하지만 웬걸... Next13부터 app router가 출시되면서 갑작스레 서버와 관련된 유틸들이
매우 많이 내장되기 시작했습니다.

간단하게 표로 정리해보았습니다.

기능 / 라우팅 유형pages routerapp router
라우팅 경로pages/post.tsxapp/post/page.tsx
라우팅 유형기본적으로 클라이언트기본적으로 서버
복잡성낮음높음
성능비교적 나쁨좋음
유연성비교적 나쁨좋음

라우팅 경로에서만 볼 때도, 원래는 pages 내에 바로 path 이름으로 파일을 만들면 해당 path가 라우팅 됐었습니다.

app router로 바뀌면서는...

  1. 'page'로 명시를 해주어야 페이지가 라우팅이 됩니다.
  2. 아무것도 명시하지 않으면 기본적으로 서버 중심으로 작동합니다.
  3. server component와 client component라는 개념을 두어 서버와 관련된 처리 또한
    전문적으로 핸들링할 수 있게 도와줍니다.

이런 단서들을 보면, Next.js의 app router는 서버 기능을 중심적으로 개발된 것이라고 추측할 수 있습니다.

이를 보면 두 번째 질문인, 기본적으로 서버 중심으로 세팅이 되어있는 이유가 무엇인지에 대해서도
궁금증이 자연스럽게 풀리게 됩니다.

그렇다면 바로 세 번째 질문을 server component와 client component와 함께 설명하겠습니다.

글의 가독성을 위해 다음과 같이 표시하겠습니다:
server component -> RSC (React Server Component)
client component -> RCC (React Client Component)

app router에서는 SSG와 SSR을 어떻게 사용할 수 있나요?

저도 app router에 대해 자세히 몰랐을 때 굉장히 많이 들었던 의문입니다.

그렇다면, SSR == RSC 인건가요?

어떻게 생각하시나요? 정답은 X입니다.
먼저 이 개념을 이해하기 위해, RSC와 RCC에 대해서 알아보겠습니다.

RSC vs RCC

app router에서는 컴포넌트를 렌더링하려는 곳이 서버인지, 브라우저인지에 따라 이를 RSC, RCC로 나눕니다.
따라서 어떤 특정 컴포넌트가 월등히 좋다기 보단, 상황에 맞는 컴포넌트를 사용하는 것이 중요합니다.

RSC는 보통 데이터나 서버 리소스, 민감한 정보를 처리할 때 자주 사용됩니다.
RCC는 브라우저 단에서 사용자의 이벤트 등을 처리할 때 자주 사용됩니다.

pages router에서는 페이지 전체를 서버 사이드로 렌더링할지, 클라이언트 사이드로 렌더링할지만
정할 수 있었는데, 이를 컴포넌트 단위로 쪼갠다면 어떻게 작동하는 걸까요?

RSC & RCC 동작 방식

(giyeon님의 글에서 더욱 자세히 확인하실 수 있습니다)

사용자가 Next 서버에 페이지를 요청하면, 서버는 위처럼 생성된 컴포넌트 트리를 직렬화된 json으로 재구성하는 작업을 진행합니다.

만약 RCC일 경우에는 컴포넌트를 해석하지 않고 "RCC가 렌더링되는 위치입니다" 하는 placeholder만을 배치해줍니다.

도출된 결과물을 클라이언트가 서버에게 미리 전달받고, 모듈 타입이 RCC일 경우 이를 렌더링해 DOM에 반영하는 방식으로 작동합니다.

잘못된 트리 구성

RSC에서 RCC를 자식 컴포넌트로 사용한다고 생각해보세요. 상상이 되시나요?
반대로, RCC에서 RSC를 자식 컴포넌트로 사용한다고 생각해보세요. 상상이 되시나요?

서버에서 클라이언트로 렌더링이 되는 건 쉽게 생각해볼 수 있지만,
그 반대는 플로우 자체가 조금 이상하다고 생각하실 수 있습니다.

만약 RCC -> RSC로 구조를 작성할 경우, 부모인 RCC가 렌더링 되는 '클라이언트 사이드' 시점에서
RSC가 렌더링되는 것이기 때문에 RSC를 사용하는 이유가 상실되는거죠.

그럼 RCC 하위 RSC도 RCC로 바뀌는 건가요?

아닙니다. RSC는 그대로 서버 컴포넌트의 특성을 유지하지만, RSC의 장점이라고 할 수 있는
중요한 한 가지 특성이 상실된다고 보시면 됩니다.

서버 컴포넌트 (RSC):

  • 서버에서 렌더링됨: 서버 컴포넌트는 서버에서 렌더링되어 클라이언트로 전달되는 HTML 생성
  • 상태 관리 없음: 클라이언트 측 상태 관리와 상호작용 로직이 포함되지 않음
  • 데이터 페칭: 서버에서 데이터를 로드하고 렌더링합니다.

RSC의 큰 장점 하나가 죽고 가는 것이죠. 그래서 실제로 이런 식으로 사용하면 build time에서
오류가 발생하고, 공식 문서에서도 이렇게 사용하지 말라고 권유합니다.

nextjs 한국어 문서 번역 사랑합니다

오잉? 근데 신기하게도 children으로 서버 컴포넌트를 넘겨주면 문제가 없다고 합니다.
왜냐하면 RCC는 렌더링 단에서 children의 위치만 정해줄 뿐, children에 어떤 내용이
들어있는지는 정확히 알 수 없기 때문에 가능하다고 하는데요,

children으로 렌더링시키는 것과 관련된 글은
2ast님의 벨로그 글에서 더욱 자세히 확인하실 수 있습니다.
존경합니다진짜

RSC & RCC 결론

이제 RSC와 RCC에 대해서 어느정도 알아보았습니다.
그렇다면 아까 드렸던 질문을 다시 해보겠습니다.

RSC는 SSR인가요?

RSC와 SSR, SSG는 다르다

정답은 전혀 아닙니다.

SSR은 페이지의 초기 렌더링을 서버에서 처리하고, 클라이언트에서 이를 받은 후
JS 코드를 덧붙여 상호 작용을 하는 식으로 작동합니다.

RSC는 서버에서 컴포넌트를 직렬화해 클라이언트로 이를 미리 전송하고,
그걸 클라이언트가 받아서 해석한 후 초기 렌더링을 진행하는 것이죠.

서버 단에서 실행된다는 개념 외에는 둘의 역할과 목적 자체가 아예 다릅니다.

RSC와 SSR은 다르다는 거군요. 그럼 app router에서는 SSR & SSG를 어떻게 구현하는지 알려주세요.

저도 이런 의문이 들었는데요, 공식 문서를 자세히 읽어보면 충격적인 사실을 알 수 있습니다.

바로 사용자가 따로 설정할 필요가 없다는 거죠!!!

pages router에서는 개발자가 SSG, SSR 둘 중 애플리케이션의 특징에 맞게 어떤 렌더링 방식이
더욱 적합한지 고민하고 이를 선택해야했습니다.

하지만 app router에서는 이런 고민을 할 필요가 없어요.

기본적으로 Next.js의 app router는 SSG 방식으로 렌더링됩니다.
그러다가 캐싱되지 않은 데이터 또는 동적 함수를 찾으면, 자동으로 내부에서 SSR을 채택합니다.

뿐만일까요? 렌더링 작업을 청크로 쪼개어 효율적으로 렌더링하는 '스트리밍'이라는 기술이 있습니다.
네 맞습니다, app router에서는 이것 또한 내장되어있기 때문에 자동으로 지원해줍니다.

그러니까 app router에서는 SSG & SSR 자동 최적화 + Streaming까지 아주그냥 럭키비키가 따로 없다 이말입니다 ~!!

무조건 app router가 좋은가요?

현재 기준으로 Next.js는 app router를 추천하고 있습니다. 하지만 어플리케이션의
특성에 따라 router를 설정할 수 있습니다.

Next.js가 낸 라우팅 유형의 컨셉에 맞게, 만약 클라이언트 사이드 목적으로 사용한다면 pages router를,
풀스택 프레임워크로 사용한다면 app router를 도입해보는 것을 추천드립니다.

마무리

요즘 공부하며 많이 느끼는 점은, 모든 상황에서 언제나 우수한 경우의 개발론은 찾기 어렵단 것입니다.
어플리케이션의 특성을 잘 이해하고, 이에 따른 프레임워크와 기술을 도입하는 것을 추천드립니다.

공부하다가 갑자기 쓰고 20분컷 낸 글이라서 다소 어색하고 틀린 부분이 있을 수 있습니다.
틀렸거나 아직 종결되지 않은 사안에 따른 좋은 피드백은 언제나 환영입니다!!

SSR보단 SSG가, SSG보단 롯데자이언츠가 짱입니다 화이팅~

참고한 자료

https://velog.io/@giyeon/Next.js-React-Server-Component

https://funveloper.tistory.com/214

https://nextjs-ko.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations#revalidating-data

https://nextjs.org/docs/app/building-your-application/rendering/server-components#static-rendering-default

https://nextjs.org/docs/app/building-your-application/rendering

https://velog.io/@yyeonggg/Nextjs-Nextjs%EC%97%90%EC%84%9C-%EC%99%9CReact-Query%EB%A1%9C-%EC%BA%90%EC%8B%B1%EC%9D%B4-%EC%95%88%EB%90%A0%EA%B9%8C

https://velog.io/@nab5m/Next-js%EC%9D%98-%EC%BA%90%EC%8B%B1

https://fe-developers.kakaoent.com/2024/240418-optimizing-nextjs-cache/

https://nextjs.org/docs/app/building-your-application/routing/route-handlers

https://nextjs.org/docs/app/api-reference

https://velog.io/@minsang9735/NextJS%EC%97%90%EC%84%A0-React-Query%EB%A5%BC-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94%EA%B2%8C-%EB%A7%9E%EC%9D%84%EA%B9%8C

https://velog.io/@jkatie1027/Next13%EC%97%90%EC%84%9C-React-Query%EB%A5%BC-%EC%99%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EA%B1%B8%EA%B9%8C

https://velog.io/@hwon3814/NextJS-v13-App-Router%EC%9D%98-%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%B0%8DSSR-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0

https://www.inflearn.com/community/questions/1137250/ssr%EA%B3%BC-rsc%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90%EC%97%90-%EA%B4%80%ED%95%98%EC%97%AC-%EC%A7%88%EB%AC%B8%EC%9D%B4-%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4

https://velog.io/@2ast/React-%EC%84%9C%EB%B2%84-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8React-Server-Component%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EC%B0%B0

profile
프론트엔드 공부중

2개의 댓글

comment-user-thumbnail
2024년 8월 11일

좋은 글 잘 보고 갑니다

1개의 답글