3 분 소요

Server-Side-Rendering (서버 사이드 렌더링)

렌더링은 간단하게 데이터와 UI 컴포넌트를 결합하여 사용자에게 시각적으로 표시하는 과정 이렇게 정의될 수 있다. 이 과정은 다음과 같이 두 가지 주요 형태로 나눌 수 있다.

  1. 서버사이드 렌더링 (SSR): 서버에서 데이터를 가져와 HTML을 생성하고, 이 HTML을 클라이언트 (브라우저)로 보내어 사용자에게 적시 렌더링하는 방법.
  2. 클라이언트사이드 렌더링 (CSR): 클라이언트(브라우저)에서 자바스크립트로 데이터를 가져와 UI를 렌더링하는 방법.

오늘은 그 첫번째 방법인 서버사이드 렌더링에 대해서 알아보겠다. 정확하게 말하자면 Next.js 프레임워크 안에서 서버사이드 렌더링이 어떤식으로 구현되는지에 대해서 알아보겠다.

서버 컴포넌트 (Server Component)

Next.js 버전 13 이후 부터 모든 컴포넌트가 기본적으로 서버 컴포넌트로 간주된다. 서버 컴포넌트는 데이터 패칭 (Data fetching)이 서버에서 실행되고 서버에서 랜더링된 결과 (HTML)을 클라이언트로 전송한다.

아래 그림을 보면 더 쉽게 이해가 될 수 있다.

SC_1

그림의 코드를 보면 프론트 서버 측 (서버 컴포넌트)가 API를 바로 호출해서 상품 데이터 (products)를 가져오고, 서버에서 렌더링된 HTML을 클라이언트에게 전달한다. 이를 통해 초기 로딩 시간을 줄이고 SEO에 최적화 할 수 있게 된다. 한가지 예를 더 들어보겠다. 아래 코드는 상품별 페이지를 나타내는 코드이고, Next.js에서 동적 페이지로 구현되었다.

/src/app/products/[id]/page.tsx

SC_2

위 두가지 예시들은 페이지 컴포넌트라 Next.js 에서 제공하는 서버사이드 렌더링 함수, ex.: getServerSideProps()를 사용하여 서버 사이드 렌더링을 구현할 수 있다. 그렇다면 페이지 컴포넌트가 아닌 다른 컴포넌트를 서버 컴포넌트로 구현하여 데이터를 패칭하는 경우가 어떤게 있을까?

페이지 컴포넌트가 아닐때 서버 컴포넌트로 사용하는 경우

한가지 대표적인 예로 “상품 리뷰 컴포넌트”를 들 수 있겠다. 폴더 구조는 다음과 같다.

SC_3

상품별 동적 페이지 안에는 이제 Reviews 라는 컴포넌트가 추가 되었고, 이 Reviews 컴포넌트는 productIdprops로 받아 상품별 리뷰들을 브라우저에 나타낸다.

SC_4

그리고 Reviews 컴포넌트:

SC_5

이 코드를 보면 Reviews 컴포넌트가 서버 컴포넌트로서 사용 되어진것을 알 수 있다. 이 컴포넌트는 페이지 컴포넌트가 아니다. 따라서 getServerSideProps() 와 같은 함수 사용이 불가하다.

이 컴포넌트가 서버 컴포넌트로서 사용되어질 수 있는 또 하나의 이유는

“이 컴포넌트는 클라이언트에서 사용자랑 직접적인 상호작용이 필요하지 않다”

는 점이다. 클라이언트랑 직접적인 상호작용이 없기 때문에 굳이 클라이언트에서 렌더링을 할 필요가 없는 것이다. 만약 서버에서 바로 데이터 패칭을 하지 않고 Redux와 같은 라이브러리를 사용해서 데이터 패칭을 했었다면 다음과 같이 구현이 되었을 것이다.

SC_6

이 경우 이 Reviews 컴포넌트가 렌더링이 되면

  1. useEffect()안에 있는 dispatch(fetchReviewsRequest(productId))가 실행이 되면서
  2. 리퀘스트는 리듀서로 가서 리퀘스트 시 상태가 업데이트 되고
  3. (Redux-saga를 사용한다고 가정했을 때) Saga에서 리퀘스트를 감지해 처리가 된다.
  4. 처리 후 결과 값은 다시 리듀서로 넘어가서 결과 (SUCCESS 또는 FAIL)에 따라 상태가 업데이트 되며
  5. 스토어에 저장이 된다.
  6. 스토어에 저장된 상태값들은 다시 해당 컴포넌트에서 useSelector()로 불려져서 사용된다.

Redux 와 같은 중앙 상태 관리 라이브러리는 복잡한 상태 관리가 필요하거나 여러 컴포넌트에서 상태를 공유해야하는 경우에는 유용하지만, 데이터 패칭 및 상태 관리가 복잡해질 수 있다. 서버 컴포넌트를 사용해 간단한 데이터 패칭을 구현하게 되면 코드가 간결해지고 중간의 Redux 의 디스패치와 상태 관리 과정을 생략할 수 있다. 이렇게 하면 데이터 로딩 속도가 빨라지고 코드를 더 간결하게 유지할 수 있게 된다.

getServerSideProps() 함수

이 함수는 Next.js에서 제공하는 서버사이드 렌더링을 구현할 때 사용하는 함수 중에 하나이다. 이 함수는 페이지 수준에서 서버 사이드 렌더링을 수행할 때 사용한다. “페이지 수준” 이란, 특정 URL 경로에 해당하는 페이지 컴포넌트를 말한다.

getServerSideProps-1

이 경우 상품 페이지 컴포넌트 안에서 getServerSideProps를 사용해 서버측에서 데이터 패칭을 해서 결과로 나온 product를 props로 넘겨줘서 ProductPage 가 그것을 받아서 쓰게 된다.

하지만 사실 ProductPage의 예시는 getServerSideProps를 위한 적합한 예시는 아닐 수 있다. 왜냐하면 이 페이지 컴포넌트는 데이터 패칭 자체가 그렇게 복잡하지 않기 때문에 서버 컴포넌트로서 사용을 해도 되기 때문이다. getServerSideProps 는 보다 더 복잡한 데이터 패칭 로직이나 서버측에서만 가능한 특정 작업을 수행할 때 유용하다.

하지만 “복잡한 데이터 패칭” 이란 무엇일까?

쇼핑몰 사이트의 사용자 대시보드를 예로 들어 보겠다. 쇼핑몰 사이트의 사용자 대시보드 페이지는 사용자의 주문내역, 사용자 프로필 정보, 추천 상품 등을 한 페이지에서 모두 가져와야 한다. 이 경우 각기 다른 API 엔드포인트에서 데이터를 가져와야 하고, 데이터 패칭 로직이 매우 복잡해질 수 있다.

이러한 상황에서 서버 컴포넌트 대신 getServerSideProps를 사용하여 데이터 패칭을 수행하는 것이 더 효율적일 수 있다. 이렇게 하면 데이터 패칭 로직을 한 곳에 모아서 관리할 수 있고, 서버사이드 렌더링의 이점을 그대로 활용할 수 있다.

getServerSideProps-2

위 그림을 보면 user, orders 그리고 recommendations 는 서로 다른 API 엔드포인트에서 온 결과 값이고 getServerSideProps 를 통해 한번에 props로 묶어서 해당 페이지 컴포넌트로 전달된다.

댓글남기기