React

React & Next.js 활용해보기 / CSR vs SSR

startfront 2025. 4. 14. 15:16

SPA란?

SPA (Single Page Application)
말 그대로 한 개의 페이지로 구성된 애플리케이션

✅ 기존 방식 (MPA: Multi Page Application)

  • 페이지 이동 시마다 새 HTML을 서버로부터 받아옴
  • 페이지마다 서버가 새로 해석 후 렌더링
  • 느리고, 화면 전환 시 깜빡임 발생

✅ CSR 기반 SPA 방식

  • 처음에 한 번만 HTML과 JS를 받아옴
  • 이후에는 브라우저에서 필요한 부분만 업데이트
  • 서버는 데이터를 제공하고, 뷰 렌더링은 클라이언트(브라우저)에서 처리

React와 CSR (Client-Side Rendering)

React는 SPA 구현을 위한 대표적인 라이브러리

✅ CSR 특징

  • 초기 HTML은 거의 비어 있음
  • 브라우저에서 JS가 실행되며 React가 컴포넌트를 렌더링
  • **가상 돔(Virtual DOM)**을 통해 필요한 부분만 업데이트 → 실제 DOM 반영

✅ 라우팅

  • 여러 주소에서 다른 화면을 보여주는 기능
  • React Router를 사용하여 구현
    • <Routes>, <Route> 사용
    • 중첩 라우팅 시 <NavLink> 등으로 처리
  • 클라이언트 사이드에서 작동하는 라우팅
  • => 서버에 새로 요청하지 않고, JS로 미리 불러온 컴포넌트만 바꿔 보여주는 방식

Next.js와 SSR (Server-Side Rendering)

Next.js는 기본적으로 SSR 기반의 프레임워크입니다.

✅ SSR이란?

클라이언트가 페이지를 요청할 때, 서버에서 HTML을 완성해서 보내주는 방식

✅ Next.js의 SSR 동작 방식

  • 모든 컴포넌트가 기본적으로 서버 사이드에서 먼저 렌더링
  • 초기 로딩 속도가 빠르고, SEO에 유리

✅ SSR의 장점

  1. 페이지 로딩 속도가 CSR보다 빠름 (초기 페이지)
  2. 검색 엔진 최적화(SEO) 가능

❗ SSR의 단점

  • 초기 로딩 이후 페이지 이동 시 서버 요청이 계속 발생 → 다소 느릴 수 있음

SSR에서 CSR로 전환이 필요한 경우

Next.js는 기본이 SSR이지만,=> 특정 상황에서는 CSR로 전환!!!

✅ 대표적인 경우: 훅(Hook) 사용 시

  • useEffect, useState 같은 React 훅은 브라우저 환경에서만 작동
  • 이 때는 CSR 방식으로 처리되어야 정상 작동
 CSR vs SSR 정리

 

  CSR SSR
설명 초기 HTML은 비어 있고, JS가 실행되며
React 컴포넌트를 렌더링
클라이언트 요청마다 서버에서
새로운 화면(View)을 만들어 전달
대표 프레임워크 CRA (Create React App) 기반 React Next.js
초기 로딩 속도 느림
=>전체 파일을 다운로드한 후 렌더링
빠름
=>HTML이 서버에서 생성되어 바로 전달
인터렉션 속도 빠름
=>브라우저에서 렌더링하므로 빠른 반응성 제공
느릴 수 있음
=>페이지 이동 시마다 서버 요청이 필요
새로고침/페이지 이동 새로고침 없음
=>네이티브 앱과 비슷한 사용자 경험 제공
페이지 이동 시 새 요청 발생 가능
서버 트래픽 감소
=> 클라이언트에서 View 렌더링 처리
증가
=> 요청마다 서버에서 HTML 생성
SEO
(검색 엔진 최적화)
불리함
=>JS를 무시하면 화면을 수집하지 못함
→ sitemap 등 보완 필요
유리함
=>검색엔진이 HTML 구조를 바로 인식
JS 비활성 시 동작
=> JS가 없으면 화면이 보이지 않음

=>서버에서 생성된 HTML이 바로 보임
기타 참고 사항 구글은 JS 렌더링을 지원하지만,
다른 검색엔진은 그렇지 않을 수 있음
-

.


Next.js 수동 설치하기

프로젝트 이름은 소문자로만, 두 단어 이상일 때는 케밥 케이스로 만든다.

  1. npm init -y
  2. npm i react next react-dom
  3. package.json을 열어 test 지우고 dev 스크립트 추가하기
"scripts": {
  "dev": "next dev"
}

 

=> Next.js를 사용할 경우엔 react-scripts 대신 Next.js가 제공하는 명령어

 

4. npm run dev 실행


Next.js 자동 설치하기

설치 순서

  1. 가장 최근 버전으로 생성 → npx create-next-app
  2. npm으로 설치하기 → npx create-next-app --use-npm
  3. 특정 버전으로 설치하기 → npx create-next-app@버전 --use-npm
  4. 설치 옵션 선택

=> import alias 설정 여부 선택

=> Next.js에서는 기본적으로 @를 src/ 폴더에 매핑 => tsconfig.json에서 변경 가능

=> Next.js는 버전에 따라 내부적으로 사용하는 **빌드 도구(번들러)**가 바뀜

=> 예전에는 Webpack, 지금은 Turbopack

📁 Next.js 디렉토리 구조 정리

my-next-app/
│
├── public/           # 정적 파일(이미지, 아이콘, 폰트 등)을 위한 디렉토리
│                     # 접근 경로: /이미지파일명
│
├── src/              # 주요 소스 코드가 포함된 디렉토리
│   ├── app/          # App Router 기반 라우팅 설정 (Root segment)
│   │                 # → 페이지 구성, 라우팅 처리 (SSR/CSR 지원)
│   │
│   ├── components/   #  재사용 가능한 UI 컴포넌트 모음
│   │                 # → 버튼, 카드, 폼 등 공통 컴포넌트
│   │
│   ├── services/     #  Ajax 요청(API 호출)을 위한 파일
│   │                 # → axios, fetch 등 비즈니스 로직 처리
│   │
│   ├── store/        #  전역 상태 관리(store)를 위한 디렉토리
│   │                 # → Redux, Zustand 등 전역 상태 저장
│   │
│   ├── styles/       #  CSS, SCSS, 모듈 스타일 등을 위한 디렉토리
│   │                 # → 전역 스타일, 변수 설정 등
│   │
│   ├── types/        #  TypeScript의 타입 정의를 위한 디렉토리
│   │                 # → 인터페이스, 타입 정의 모음
│   │
│   └── utils/        # 자주 사용하는 유틸 함수들을 위한 디렉토리
│                     # → 날짜 포맷팅, 숫자 변환, 공통 로직 등
│
├── .next/            # Next.js가 빌드한 결과물이 저장되는 디렉토리
│                     # → 자동 생성됨. 배포 시 포함 X
│
├── package.json      # 프로젝트 메타정보 및 의존성
└── next.config.js    # Next.js 설정 파일 (필요 시 생성)

 

✅Next.js에서 이미지 다루기

Next.js는 기본이 SSR이기 때문에, 이미지 파일은 반드시 public 폴더에 넣어야 한다.

🔍 왜?

  • SSR에서는 서버가 HTML을 생성해서 클라이언트로 보내기 때문에,
  • **이미지를 import하는 방식(CRA 스타일)**이 아닌, 경로 기반 접근이 필요
  • 따라서 이미지 파일은 **정적 자원(static assets)**으로 처리되어야 하고,
  • 이를 위해 Next.js는 /public 폴더를 기본 정적 파일 경로로 사용

✅ 브라우저 자동으로 열기 설정 (package.json)

next dev 실행 시 브라우저가 자동으로 열리게 하기 위해, package.json에 스크립트를 추가

  1. package.json 파일
  2. 아래와 같이 스크립트를 추가
"scripts": {
  "dev": "npm run open-browser && next dev",
  "open-browser": "start http://localhost:3000"
}
 
 

✅ Next.js App Router: 폴더 = 경로(Path)

Next.js(App Router 구조, src/app/)에서는 디렉토리 구조가 곧 URL 경로가 됩니다.

📁 폴더 = 경로
📄 page.tsx 또는 page.jsx = 해당 경로의 페이지

 

page.tsx 파일은 필수!!!
해당 폴더가 라우팅 가능한 페이지가 되려면 반드시 필요

 
"use client"; // 클라이언트 컴포넌트임을 명시

import React from "react"; 
import styles from "./Navigation.module.css";
import Link from "next/link";

const Navigation = () => {
  return (
    <nav className={styles.nav}>
      <ul className={styles.menu}>
        <li><Link className={styles.menu_item} href="/">Home</Link></li>
        <li><Link className={styles.menu_item} href="/about-us">AboutUs</Link></li>
        <li><Link className={styles.menu_item} href="/book">Book</Link></li>
        <li><Link className={styles.menu_item} href="/book/book-insert">book insert</Link></li>
      </ul>
    </nav>
  );
};

export default Navigation;
 

✅className={styles.menu_item} 왜 이렇게 쓰는 걸까?

 1. CSS Module 방식이라서

 

Next.js에서는 *.module.css 파일을 쓰면 CSS Module로 인식
=> 클래스명이 자동으로 고유한 이름으로 바뀌어서 충돌 없이 사용

 

 2. 일반적인 클래스와 비교해보면?

 

방식코드설명
일반 CSS className="menu_item" 전역 클래스. 다른 컴포넌트와 충돌 가능성 있음
CSS Module className={styles.menu_item} 컴포넌트 단위로 분리. 클래스명이 내부적으로 유니크하게 변환됨

 

✅페이지 이동: a 태그 대신 Link 태그 사용

Next.js에서는 클라이언트 사이드 라우팅을 위해 반드시 <Link> 컴포넌트를 사용

<Link href="/about-us">About Us</Link>
 
 
📁 App Router 디렉토리에 사용하는 주요 파일들

 

파일명 설명
page.tsx 해당 경로에 대한 페이지 컴포넌트 (필수)
layout.tsx 해당 경로 이하에 공통으로 적용되는 레이아웃
loading.tsx 페이지가 로딩 중일 때 보여줄 컴포넌트
error.tsx 렌더링 도중 오류 발생 시 보여줄 에러 컴포넌트
not-found.tsx 404(존재하지 않는 경로) 접근 시 보여줄 컴포넌트 / app>not-found.tsx 배치 : 전역 설정

Private Directory란?

라우팅과 관계없는 디렉토리임을 명시하기 위해 디렉토리 이름 앞에 _(언더스코어)를 붙이는 관례

 
=> 로직 분리 및 시각화
형식]   _directory-name
 

 

(home) 폴더 사용하기

App Router에서 특수 폴더 이름

 (home) 폴더는 실제 라우팅 경로에 영향을 주지 않는 그룹 폴더입니다.

즉, 내부에는 여러 파일이 들어갈 수 있지만
URL 경로에서는 전혀 드러나지 않는다!!!!!


Dynamic Routes (동적 라우팅)

 개념

**Path Variable(경로 변수)**를 사용해서,
동적으로 특정 데이터를 표시하는 페이지를 만들고 싶을 때 사용하는 라우팅 방식

 

예를 들어 /book/12345처럼 특정 isbn 값에 따라 상세 페이지를 렌더링할 때 사용

 

디렉토리 구조

src/
└── app/
    └── book/
        └── [isbn]/        ✅ Path Variable로 처리
            └── page.tsx

📂 대괄호 [ ] 안에 들어간 이름이 URL에서 변수처럼 작동합니다.

 

파일 내용 ([isbn]/page.tsx)

import React from "react";

// params로부터 Path Variable 'isbn' 추출
const BookDetail = ({ params: { isbn } }: { params: { isbn: string } }) => {
  console.log("isbn", isbn);

  return (
    <div>
      <h1>Book Detail : {isbn}</h1>
    </div>
  );
};

export default BookDetail;

 

실제 URL 호출 예

URL동작
http://localhost:3000/book/12345 isbn 값으로 12345 전달
http://localhost:3000/book/98765 isbn 값으로 98765 전달

=> 위 URL들은 모두 동일한 [isbn]/page.tsx 파일을 사용하여 페이지가 동적으로 생성

 

동적 라우팅 활용

import Link from "next/link";
import React from "react";

// 소문자로 시작하는 컴포넌트는 비권장
const book = () => {
  return (
    <div>
      <div>
        <Link href="./book/1">1111</Link>
      </div>
      <div>
        <Link href="./book/2">2222</Link>
      </div>
    </div>
  );
};

export default book;

 

  • /book 경로에서
    ./book/1, ./book/2 링크 클릭 시 각각 book/1, book/2 경로로 이동
  • 해당 경로에 있는 동적 라우트:
    src/app/book/[isbn]/page.tsx 에서 isbn 값을 받아 상세 페이지 출력


Next.js에서 훅 사용

✅ 훅(Hooks) 사용 = CSR이 필요!

Next.js는 기본적으로 SSR(Server Side Rendering) 기반 프레임워크
즉, 컴포넌트는 기본적으로 서버에서 먼저 렌더링

 

하지만!

 

useState, useEffect, usePathname 같은 **React 훅(Hook)**은 브라우저에서만 동작

 

그래서 이런 훅을 사용하는 컴포넌트는 **클라이언트 사이드 렌더링(CSR)**이 되어야 한다!!!1

 

이를 Next.js에 명시적으로 알려주는 지시어

"use client";

 

✅ 예제 코드: 현재 경로(path)에 따라 메뉴 강조하기

"use client"; // 클라이언트 컴포넌트로 선언 (CSR 전환)

import React from "react";
import styles from "./Navigation.module.css";
import Link from "next/link";
import { usePathname } from "next/navigation";

const Navigation = () => {
  const path = usePathname(); // 현재 브라우저의 경로 가져오기

  return (
    <nav className={styles.nav}>
      <ul className={styles.menu}>
        <li>
          <Link className={styles.menu_item} href="/">
            Home{path === "/" ? "🔥" : ""}
          </Link>
        </li>
        <li>
          <Link className={styles.menu_item} href="/about-us">
            AboutUs{path === "/about-us" ? "😍" : ""}
          </Link>
        </li>
        ...
      </ul>
    </nav>
  );
};

export default Navigation;

✅ 동작 방식!!!!!!

  • usePathname() 훅을 통해 현재 주소를 알아냄
  • 그 주소와 메뉴 항목 경로가 같으면 이모지를 붙여 강조
  • 이 동작은 브라우저에서만 가능하기 때문에 use client가 꼭 필요

✅JS를 끄면 어떻게 될까?

CSR은 브라우저에서 JS가 실행되어야만 렌더링이 완료
=> 따라서 브라우저에서 JavaScript를 꺼버리면 

  • 화면이 안 뜨거나 비정상 렌더링
  • usePathname이 작동하지 않음 (경로 강조 기능도 안 됨)
  • 기본 HTML만 보일 수 있음

반대로 SSR은 JS 없이도 기본 화면은 보여줄 수 있다!!(서버가 HTML을 만들어서 보내니까)