과거에 html 도큐먼트를 읽기 위해서 개발된 HTTP 프로토콜을 더욱 더 발전시키기 위해서
설계 매커니즘에는 UI / 데이터 / 제어체계를 분리시키자는, 이른바 MVC 패턴이 등장했다.
이에 UI와 데이터를 분리시키는 과정에서 데이터는 Json이나 XML로 보내고,
UI는 자바스크립트 기반 언어를 이용해서 위에서 받은 자료를 가지고 동적으로 HTML을 생성하게 되었다.
이 기술은 유저들이 사용하는 디바이스가 점점 더 많아짐에 따라(각 디바이스마다 인치수가 다르므로)
독립된 기술로 발전했는데, 바로 React.js와 Vue.js 같은 툴의 등장 되시겠다.
그리고 이것을 넘어서서, React의 기능을 기반으로 SSR을 하기 위해 나온 풀스택 웹 어플리케이션 프레임워크인
Next.JS
가 등장했다.
Next.JS
는 React 기술 기반인 만큼 프론트엔드는 리액트로 구현하고, 백엔드는 Express.JS와 비슷한 원리로 구현된다.
풀스택 프레임워크인 만큼, 개발자는 더 이상 프론트에 3000 포트를 띄움과 동시에, 백엔드에 8080 포트를 띄울 필요성이 없어졌고, CORS같은 복잡한 설정도 할 필요 없이 개발에만 집중하면 되는 장점을 누릴 수 있다.
CSR과 SSR은 서로 장단점을 가지고 있지만, SSR방식을 채택할 경우 유저에게 더 빠른 페이지 로드와
자바스크립트가 있지 않아도 서버에서 html 도큐먼트를 생성해서 클라이언트에 보낸다는 점에서 SEO(검색 엔진)과 같은 로봇에게도 친화적이다. 그래서 내가 만든 웹 어플리케이션을 남들에게도 더 많이 알릴 수 있다는 장점또한 존재한다.
이 글에서는 Next.JS 13을 다룰 것이다. Next는 App Router를 위해 기존 버전과의 하위호환성을 전부 버릴 정도로 큰 결심을 단행했다. 하위호환성을 가장 중요시하는 Java/Spring과는 확연히 다른 행보이며, 이 App Router가 무엇이길래 Next.JS가 하위호환성을 포기했는지부터 알아보자.
App Router란 무엇일까?
공식 문서(https://nextjs.org/docs/app/building-your-application/routing)에서는 App routing을 다음과 같이 설명하고 있다.
In version 13, Next.js introduced a new App Router built on React Server Components, which supports shared layouts, nested routing, loading states, error handling, and more.
버전 13에서 Next.js 는 공유 레이아웃, 중첩 라우팅, 로딩 상태, 오류 처리 등을 지원하는 React Server Components를 기반으로 구축된 새로운 앱 라우터를 도입했습니다.
Next.js는 기존의 '페이지 라우터'라는 기술을 버리고, 새롭게 '앱 라우터'라는 기술을 도입할 만큼 '라우터'를 기반으로 동작한다.
라우터가 무엇이냐고 물으면, 나는 '표지판'이라고 대답할 것이다.
라우터는 데이터에게 어디로 가야하는지에 대한 경로를 표시해 주기도 하고, 특정 데이터를 어디에 보내는 '라우팅'의 역할도 한다.
앱 라우터는 src/app 밑에서 동작하는데, file system(directory)를 기준으로 데이터를 보낸다.
예를 들어 내가 'localhost:3000/create' 페이지를 만들고 싶으면,
src/app
├─layout.js
├─page.js
└─create
└─page.js
이렇게 만들면 된다는 것이다.
과거의 페이지 라우터는 다음과 같은 방식으로 만들었어야 했다.
src/pages
├─_app.js
├─index.js
└─create.js
이러다 보니, 전체 페이지가 난잡해질 뿐 아니라 코드가 복잡해지면 js파일이 너무 무거워진다는 단점또한 존재한다.
앱 라우터는 페이지 라우터보다 먼저 동작하고,리액트 서버 컴포넌트를 기반으로 구축된다.
앱 라우터와 페이지 라우터의 비교에 대한 추가적인 설명은
https://www.timegambit.com/blog/blog-log/app-router
를 보면 이해하기 쉽다.
Server Component
서버 컴포넌트란 무엇인가?
리액트18부터 도입된 리액트 서버 컴포넌트는 기존의 컴포넌트로 인식된 '클라이언트 컴포넌트'와는 다르게
서버에서 컴포넌트를 렌더링한 후 제공한다.
이를 위해선 하이드레이션(Hydration)이 무엇인지 알 필요가 있다.
클라이언트에서 한꺼번에 조립되는 CSR방식과는 달리,
SSR에서는 서버에서 먼저 완성된 정적인 HTML 도큐먼트를 클라이언트에 보내고, 리액트에서 JS를 번들링(이미지, 폰트, CSS등을 js로 변경해서 보내는 것)해서 보내면 클라이언트에서 이를 조립해서 동적인 페이지로 변화시키는 것이다.
이를 '물에 준다'는 뜻으로, Hydrate라고 부른다.
일반적으로, 서버 컴포넌트들은 Hydrate 이후에는 재사용 할 수 없다.
그러나 React server component를 사용하면 hydrate 이후에도 컴포넌트들을 사용할 수 있다.
그래서 RSC(React Server Component)는 SSR과 함께하는 개념이라기보다는, SSR을 보완해주는 개념이라고 볼 수 있다.
서버 컴포넌트 vs 클라이언트 컴포넌트
서버 컴포넌트
- 서버에서 직접 데이터 가져오기
- 보안에 민감한 정보에 안전하게 접근
- 렌더링에 필요한 라이브러리를 번들에 포함하지 않음으로써 JS 사이즈 줄이기
클라이언트 컴포넌트
- onClick, onChange와 같은 이벤트 리스너
- useState, useReducer, useEffect와 같은 상태와 생명주기
- browser에서 사용할 수 있는 api
- state, effect, brower api를 사용하는 커스텀 훅
이렇게 서버 클라이언트와 클라이언트 컴포넌트가 하는 일은 명확하게 구분되어있다. 그래서 가장 중요한 것이
이 컴포넌트들을 적재적소에 잘 이용하는 것이다.
그리고 클라이언트 컴포넌트를 이용하기 위해서는 'use client'를 명시해주면 되는데, 이는 다음에 확인하자.
참조
App router / Pages router 비교
Server components
- https://velog.io/@2ast/React-서버-컴포넌트React-Server-Component에-대한-고찰
- https://ui.toast.com/weekly-pick/ko_20210119
hydration