본문 바로가기

[Dev] 🎯Self Study

[리액트에서 Next로] Next.js 기초 : SSR, CSR 렌더링 차이와 특징

 

Next에서는 컴포넌트를 렌더링하는 2가지 방식이 존재한다.


1. client 의 web browser -> CSR (클라이언트 사이드 렌더링, 리액트와 유사)

2. server의 node.js 런타임 -> SSR (서버 사이드 렌더링)

 

Client-Side Rendering (CSR) Server-Side Rendering(SSR)


큰 사이즈의 번들 크기
리소스 집약적
검색 엔진 최적화 어려움 (SEO)
낮은 보안성

작은 번들 사이즈
리소스 최소화
검색엔진 최적화 (SEO)
높은 보안성

 

 

CSR vs. SSR

클라이언트 사이드 렌더링

우선적으로 모든 컴포넌트를 번들링해 서 클라이언트로 전달합니다.
이는 애플리케이션의 크기가 커짐에 따라 번들 크기가 커짐을 의미합니다.
번들 크기가 커지면 커질수록 클라이언트에서는 컴포넌트를 로드하 기 위해 더 많은 메모리를 사용해야 합니다.
그래서 이 방식은 리소스 집약적이라 표현합니다. 즉, 많은 컴퓨터 자원이 사용됨을 의미합니다.

또 다른 문제는 번들링된 코드가 웹브라우저에서 실행되어야 코드 가 생성되기 때문에 검색 엔진봇이 웹사이트를 스캔하는 시점에는 어떠한 내용도 표시되지 않습니다. 이는 검색 엔진 최적화를 어렵게 만듭니다.
마지막으로는 API 키와 같이 민감한 데이터가 클라이언트에 노출될 위험이 있습니다.

그렇다고 해서 클라이언트 사이드 렌더링에는 단점만 존재하는 것은 아닙니다.
최초 렌더링 시점에 빈 HTML을 렌더링하기 때문에 초기 로딩 속도가 빠르고 클릭,
마우스 스크롤 등 브라우저 API와 상호작용이 용이합니다.

하지만 여기서 꼭 알아야 할 점은 초기 로딩 속도와 렌더링 속도는 다른 것을 의미한다는 것입니다. 

서버 사이드 렌더링

클라이언트 사이드 렌더링에서 발생한 문제를 대부분 해결할 수 있습니다.
서버 사이드 렌더링은 서버에 요청이 들어왔을 때 필요한 컴포넌트만을 클라이언트로 전송함으로써
 작은 번들 사이즈를 유지할 수 있고 서버가 대부분의 렌더링을 처리하기 때문에
클라이언트에서 필요로 하는 리소스 양을 획기적으로 줄일 수 있습니다.

그리고 서버에서 모든 HTML 마크업을 생성해 클라이언트로 전송 하기 때문에 검색엔진 최적화를 구현할 수 있습니다.
또한 API 키와 같이 민감한 데이터를 서버에 유지함으로써 보안성을 높일 수 있습니다.

물론 서버 사이드 렌더링 또한 단점이 존재합니다.
- 전체 렌더링을 서버에서 담당하기 때문에 클릭, 마우스 등의 브라우 저 API와 상호작용이 불가능
- React UseStates, UseEffect 등의 Hook 사용도 불가능

Next.js는 이 두 가지 방식을 모두 사용할 수 있는 기능을 제공

 

 

상황에 따라 최적의 렌더링 방식을 선택!
Next.js의 기본 렌더링 방식은 서버사이드 렌더링



서버사이드 렌더링으로 구현된 컴포넌트 살펴보기 : 
Next.js는 기본 값으로 서버 사이드 렌더링을 사용하기 때문에, 개발자도구 - 네트워크 탭에서 결과를
확인해보면 검색 엔진 봇이 탐색할 때 보는 결과 값과 실제 렌더링 된 결과가 정확히 일치함


반면에 클라이언트 사이드 렌더링을 사용하는 경우,

이는 리액트 컴포넌트 동작 방식과 유사한데 검색 엔진봇은 탐색시 빈 페이지를 보게 된다. 

 


 

ex. 상품 목록을 보여주는 페이지를 만드는 상황 


상품 목록 페이지 구성 (컴포넌트)

 

1. navigation bar을 뜻하는 navbar 컴포넌트

2. 상품 목록을 뜻하는 product list  컴포넌트

3. 하나의 상품을 표시하는 product card  컴포넌트

4. 페이지 전환을 담당하는 pagination 컴포넌트

5. 페이지 상세 정보를 보여주는 footer 컴포넌트


- 애플리케이션에서는 모든 컴포넌트를 번들로 패키징해 클라이언트로 전달하는 방식으로 동작

 

Next.js에서는 모든 컴포넌트를 기본적으로 SSR 방식으로 렌더링하기 때문에 클라이언트로 전달하는 번들 크기를 최소화 가능


BUT, 단일 제품을 담당하는 프로덕카드 컴포넌트에는 클릭한 상품을 장바구니에 담는 버튼이 존재하는데 

이 기능은 브라우저 API를 사용해야 하기 때문에, 클라이언트 사이드 렌더링 방식으로 렌더링해야 한다.

 

프로덕트카드 컴포넌트 내부 코드를 보면 클릭 이벤트를 사용하는 부분을 제외한

나머지코드는 서버 사이드 렌더링 방식으로 렌더링 되어도 전혀 문제없음

 

-> 따라서 장바구니에 제품을 담는 기능을 담당하는 버튼에 코드만 add to cart 파일로 이동시키고

클라이언트 사이드 렌더링 방식으로 동작


= Next.js 엔진에 의해 AddToCart 컴포넌트를 제외한 모든 컴포넌트는 서버사이드 렌더링 방식으로 렌더링 

 


 

components 폴더에는 페이지 파일이 없고, 외부에서 접근할 수 없으므로, 코드 관리에 용이

 

import React from 'react'

const ProductCard = () => {
  return (
    <div>
    <h1>ProductCardComponent</h1>
    </div>
  )
}

export default ProductCard

 

 

SSR의 특징 알아보기

1. ProductCard 컴포넌트 버튼 추가

import React from 'react'

const ProductCard = () => {
  return (
    <div>
    <h1>ProductCardComponent</h1>
    <button onClick={()=> console.log("Add to cart")}>ADD</button>
    </div>
  )
}

export default ProductCard

 

 

2. 홈페이지에 ProductCard 컴포넌트 추가

import ProductCard from "@/components/ProductCard"
import Link from "next/link"

export default function Home() {
  return (
    <main>
      <h1>HELLO!!!!!</h1>
      <Link href="/users">Users_NAV</Link>
      <ProductCard/>
    </main>
  )
}

 

 

3.localhost:3000에 접속해서 새로고침


서버 컴포넌트는 브라우저 API에 접근할 수 없으므로
버튼에 클릭 이벤트를 추가하면 오류가 발생한다!

 

만약 이렇듯 브라우저 API를 이용해야하는 경우에는, 해당 컴포넌트를 Client 컴포넌트로 전환해야한다.

"use client" 지시문을 컴포넌트 최상단에 명시하면, next.js는 해당 컴포넌트를 클라이언트 컴포넌트로 간주

 

"use client";

import React from 'react'

const ProductCard = () => {
  return (
    <div>
    <h1>ProductCardComponent</h1>
    <button onClick={()=> console.log("Add to cart")}>ADD</button>
    </div>
  )
}

export default ProductCard

 

 

그러나 여기서 더 중요한 것은 정말 필요한 부분만 클라이언트 컴포넌트로 전환하고,

나머지 부분은 서버사이드렌더링을 사용해야한다는 점이다. 

 

 

따라서 새롭게 컴포넌트를 만들어 서버사이드렌더링과 구분해야한다.

 

 

1. AddtoCart 컴포넌트를 생성한 다음, ProductCard 의 버튼 부분을 옮기기 

"use client";

import React from 'react'

const AddtoCart = () => {
  return (
    <div>
    <button onClick={()=> console.log("Add to cart")}>ADD</button>
    </div>
  )
}

export default AddtoCart

 

 

2.  ProductCard의 use client 삭제, 자식요소로 AddtoCart 컴포넌트 추가

import React from 'react'
import AddtoCart from './AddtoCart'

const ProductCard = () => {
  return (
    <div>
    <h1>ProductCardComponent</h1>
    <AddtoCart/>
    </div>
  )
}

export default ProductCard

 

3. 서버 재실행

 

위와 같은 프로덕트 컴포넌트 (SSR + CSR 방식) 렌더링을 하이브리드 렌더링이라 한다.

Hybrid Rendering

Next.js의 하이브리드 렌더링은 서버 측에서 페이지를 미리 생성하는 정적 생성과 요청 시점에 페이지를 생성하는 서버 측 렌더링(SSR) 을 결합한 방식입니다.
개발자는 페이지별로 가장 적합한 렌더링 방식을 선택할 수 있어 효율성과 성능을 극대화할 수 있습니다.