๋ฐ˜์‘ํ˜•

App Router vs Page Router


๊ธฐ๋Šฅ ์•ฑ ๋ผ์šฐํ„ฐ ํŽ˜์ด์ง€ ๋ผ์šฐํ„ฐ
๋ผ์šฐํŒ… ํƒ€์ž… ์„œ๋ฒ„ ์ค‘์‹ฌ ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ
์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ์ง€์› O X
๋ณต์žก๋„ ๋” ๋ณต์žกํ•จ ๋” ๊ฐ„๋‹จํ•จ
์„ฑ๋Šฅ ๋” ์ข‹์Œ ๋” ๋‚˜์จ
์œ ์—ฐ์„ฑ ๋” ์œ ์—ฐํ•จ ๋œ ์œ ์—ฐํ•จ
ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๋ผ์šฐํŒ… ์ค‘์ฒฉ ํด๋”๋ฅผ ์‚ฌ์šฉํ•ด ๋ผ์šฐํŠธ ์ •์˜ ํŒŒ์ผ์ด ์ง์ ‘ ๋ผ์šฐํŠธ๋ฅผ ๋‚˜ํƒ€๋ƒ„
์ปดํฌ๋„ŒํŠธ  ๊ธฐ๋ณธ์ ์œผ๋กœ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ณธ์ ์œผ๋กœ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ
๋ฐ์ดํ„ฐ ํŽ˜์นญ fetch ํ•จ์ˆ˜ ์‚ฌ์šฉ getServerSideProps, getStaticProps, getInitialProps ์‚ฌ์šฉ
๋ ˆ์ด์•„์›ƒ ๋ ˆ์ด์•„์›ƒ ์ค‘์ฒฉ / ๋™์  ๋ ˆ์ด์•„์›ƒ ์ •์  ๋ ˆ์ด์•„์›ƒ
๋™์  ๋ผ์šฐํŠธ ์ง€์›ํ•˜์ง€๋งŒ ๋ฌธ๋ฒ• ๋‹ค๋ฆ„ Link ์ปดํฌ๋„ŒํŠธ๋กœ ์ง€์›
์šฐ์„ ์ˆœ์œ„ ํŽ˜์ด์ง€ ๋ผ์šฐํ„ฐ๋ณด๋‹ค ์šฐ์„  ์•ฑ ๋ผ์šฐํŠธ๊ฐ€ ์—†์„ ๊ฒฝ์šฐ ๋Œ€์ฒด

 

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ


  • Next.js ๋ฒ„์ „ 13~๋ถ€ํ„ฐ ์ œ๊ณตํ•˜๋Š” App Router๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ธฐ๋ณธ๊ฐ’
  • ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋Š” ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜์ง€ ์•Š์Œ → ํ•˜์ด๋“œ๋ ˆ์ด์…˜/๋ฆฌ๋ Œ๋”๋ง ๋ชจ๋‘ ์—†์Œ
    • ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋Š” UI๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์„œ๋ฒ„์—์„œ ๋”ฑ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋จ
    • ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋Š” ์„œ๋ฒ„์—์„œ๋งŒ ๋ Œ๋”๋ง๋˜๋ฏ€๋กœ JS ๋ฒˆ๋“ค์— ํฌํ•จ ์•ˆ๋จ → ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์˜ ์žฅ์ 
    • ๋•Œ๋ฌธ์— useEffect, useState ๋“ฑ React API๋Š” ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉ ๋ถˆ๊ฐ€
    • ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋Š” ๋‹ค์‹œ ๋ Œ๋”๋งํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— state๋„ ์‚ฌ์šฉ ๋ถˆ๊ฐ€
  • ๋ฐ˜๋ฉด ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” ์„œ๋ฒ„/ํด๋ผ์ด์–ธํŠธ ์–‘์ชฝ์—์„œ ๋ชจ๋‘ ๋ Œ๋”๋ง๋จ
  • ํŒŒ์ผ ์ตœ์ƒ๋‹จ์— use client ์ง€์‹œ๋ฌธ(Directive)์„ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ์˜ตํŠธ์ธ
    • ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” JS ๋ฒˆ๋“ค์— ํฌํ•จ๋จ
    • ์—„๋ฐ€ํ•˜๊ฒŒ ๋งํ•˜๋ฉด use client ์ง€์‹œ๋ฌธ์€ ํŒŒ์ผ/๋ชจ๋“ˆ ์ˆ˜์ค€์—์„œ ์ž‘๋™
  • ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” ๋‹ค๋ฅธ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋งŒ ์ž„ํฌํŠธ ๊ฐ€๋Šฅ
    • ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์—์„  ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง ๋ถˆ๊ฐ€
    • ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์—์„  ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง ๊ฐ€๋Šฅ

 

 

ํด๋ผ์ด์–ธํŠธ ๊ฒฝ๊ณ„ โญ


์•„๋ž˜ ๊ฐ™์€ ๊ตฌ์กฐ์—์„œ <Article /> ์ปดํฌ๋„ŒํŠธ์— use client ์ง€์‹œ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ชจ๋‘ ์•”๋ฌต์ ์œผ๋กœ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ณ€ํ™˜๋œ๋‹ค. ์ฆ‰, use client ์ง€์‹œ๋ฌธ์€ ํด๋ผ์ด์–ธํŠธ ๊ฒฝ๊ณ„๋ฅผ ์ƒ์„ฑํ•œ๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

ํด๋ผ์ด์–ธํŠธ ๊ฒฝ๊ณ„ โ˜ ์ด๋ฏธ์ง€ ์ถœ์ฒ˜ Josh Comeau

๋งŒ์•ฝ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋†’์€ ์ˆ˜์ค€์—์„œ(์ƒ์œ„) use client ์ง€์‹œ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด, ๋ชจ๋“  ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ(Header, MainContent)๋Š” ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋œ๋‹ค.

'use client';

import { DARK_COLORS, LIGHT_COLORS } from '@/constants.js';
import Header from './Header';
import MainContent from './MainContent';

function Homepage() {
  const [colorTheme, setColorTheme] = React.useState('light');
  const colorVariables = colorTheme === 'light' ? LIGHT_COLORS : DARK_COLORS;

  return (
    <body style={colorVariables}>
      <Header /> {/* ์•”๋ฌต์ ์œผ๋กœ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ณ€ํ™˜ */}
      <MainContent /> {/* ์•”๋ฌต์ ์œผ๋กœ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ณ€ํ™˜ */}
    </body>
  );
}

 

๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ณ€๊ฒฝ๋˜๋ฉด Next.js ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์žฅ์ ์ด ์‚ฌ๋ผ์ง€๋ฏ€๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ์ฐจ์„ ์ฑ…(workaround)์œผ๋กœ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋˜๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

 

โถ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” <ColorProvider /> ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ ๋”ฐ๋กœ ๋ถ„๋ฆฌ

// components/ColorProvider.js

'use client';

import { DARK_COLORS, LIGHT_COLORS } from '@/constants.js';

function ColorProvider({ children }) {
  const [colorTheme, setColorTheme] = React.useState('light');
  const colorVariables = colorTheme === 'light' ? LIGHT_COLORS : DARK_COLORS;

  return <body style={colorVariables}>{children}</body>;
}

 

โท <Homepage /> ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์—์„œ <ColorProvider /> ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ ์ž„ํฌํŠธํ•ด์„œ ์‚ฌ์šฉ

// components/Homepage.js

import Header from './Header';
import MainContent from './MainContent';
import ColorProvider from './ColorProvider';

function Homepage() {
  return (
    <ColorProvider>
      <Header /> {/* ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ */}
      <MainContent /> {/* ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ */}
    </ColorProvider>
  );
}

 

<Header />, <MainContent /> ์ปดํฌ๋„ŒํŠธ๋ฅผ import ํ•œ ๊ณณ์ด <Homepage /> ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ์ด๋ฏ€๋กœ, ์—ฌ๊ธฐ์„œ ๋ Œ๋”๋ง ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋“ค์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋กœ ์ž‘๋™ํ•œ๋‹ค๊ณ  ๋ณด๋ฉด ๋œ๋‹ค. ์ฆ‰, ์–ด๋–ค ์œ ํ˜•์˜ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ถˆ๋Ÿฌ์™”๋Š”์ง€์— ๋”ฐ๋ผ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์˜ ์„œ๋ฒ„/ํด๋ผ์ด์–ธํŠธ ์ž‘๋™ ๋ฐฉ์‹์ด ๊ฒฐ์ •๋œ๋‹ค.

 

 

๋ Œ๋”๋ง ํ๋ฆ„ ๋น„๊ต


๐Ÿ’ก ํŽธ์˜๋ฅผ ์œ„ํ•ด Render Shell์€ ๋ ˆ์ด์•„์›ƒ ๋ Œ๋”๋ง์œผ๋กœ ๋ฒˆ์—ญ

 

CSR

๋ชจ๋“  ์ฝ˜ํ…์ธ ๋ฅผ ํด๋ผ์ด์–ธํŠธ์—์„œ ๋ Œ๋”๋งํ•ด์„œ ์„œ๋ฒ„ ๋ถ€๋‹ด์„ ์ค„์ด๊ณ  ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒํ•œ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ์ œ๊ณตํ•˜์ง€๋งŒ, ์ดˆ๊ธฐ ๋กœ๋”ฉ ์†๋„๊ฐ€ ๊ธธ์–ด์ง€๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค. 

CSR ๋ Œ๋”๋ง ๊ณผ์ • โ˜ ์ด๋ฏธ์ง€ ์ถœ์ฒ˜ - Josh Comeau

  1. (ํด๋ผ์ด์–ธํŠธ) JS ๋ฒˆ๋“ค์„ ํฌํ•จํ•œ ๋ฆฌ์†Œ์Šค ๋‹ค์šด๋กœ๋“œ
  2. (ํด๋ผ์ด์–ธํŠธ) ๋นˆ HTML ๋ Œ๋”๋ง
    ===== ๋นˆ ํ™”๋ฉด ํ‘œ์‹œ | ์ธํ„ฐ๋ ‰์…˜ ๊ฐ€๋Šฅ =====
  3. (ํด๋ผ์ด์–ธํŠธ) ์ฝ˜ํ…์ธ  ๋‹ค์šด๋กœ๋“œ
  4. (ํด๋ผ์ด์–ธํŠธ) ์ฝ˜ํ…์ธ  ๋ Œ๋”๋ง

 

SSR

ํŽ˜์ด์ง€ ๋ผ์šฐํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด๋„ ์„œ๋ฒ„์—์„œ ์ฝ˜ํ…์ธ ๋ฅผ ๋ฏธ๋ฆฌ ๋‹ค์šด๋กœ๋“œํ•˜๊ณ  HTML์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ ๊ฐ€์žฅ ์ƒ๋‹จ์— ์žˆ๋Š” ๋ผ์šฐํŠธ ๋ ˆ๋ฒจ์—์„œ๋งŒ ์ž‘๋™ํ•˜๋Š” ๋‹จ์ ์ด ์žˆ์œผ๋ฉฐ ์ด๋ฅผ Pre-RSC๋ผ๊ณ ๋„ ๋ถ€๋ฅธ๋‹ค. ์•„๋ž˜ ์ด๋ฏธ์ง€๋Š” ๊ธฐ๋ณธ SSR ๋ Œ๋”๋ง ํ”Œ๋กœ์šฐ. CSR์— ๋น„ํ•ด First Paint๊ฐ€ ๋นจ๋ผ์ง€๋Š” ์žฅ์ ์ด ์žˆ๋‹ค. 

 

SSR ๋ Œ๋”๋ง ๊ณผ์ • โ˜ ์ด๋ฏธ์ง€ ์ถœ์ฒ˜ - Josh Comeau

  1. (์„œ๋ฒ„) ๋ ˆ์ด์•„์›ƒ HTML ์ƒ์„ฑ
  2. (ํด๋ผ์ด์–ธํŠธ) JS ๋ฒˆ๋“ค์„ ํฌํ•จํ•œ ๋ฆฌ์†Œ์Šค ๋‹ค์šด๋กœ๋“œ
    ===== ๋ ˆ์ด์•„์›ƒ ํ‘œ์‹œ | ์ธํ„ฐ๋ ‰์…˜ ๋ถˆ๊ฐ€ =====
  3. (ํด๋ผ์ด์–ธํŠธ) ํ•˜์ด๋“œ๋ ˆ์ด์…˜
    ===== ์ธํ„ฐ๋ ‰์…˜ ๊ฐ€๋Šฅ =====
  4. (ํด๋ผ์ด์–ธํŠธ) ์ฝ˜ํ…์ธ  ๋‹ค์šด๋กœ๋“œ
  5. (ํด๋ผ์ด์–ธํŠธ) ์ฝ˜ํ…์ธ  ๋ Œ๋”๋ง

 

SSR with Server Component

SSR์— ๋น„ํ•ด First Paint๋Š” ๋‹ค์†Œ ๋Šฆ์–ด์ง€์ง€๋งŒ, Content Painted(์ฝ˜ํ…์ธ  ํŽ˜์ธํŠธ)๊ฐ€ ๋นจ๋ผ์ง€๋Š” ์žฅ์ ์ด ์žˆ๋‹ค. 

SSR ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง ๊ณผ์ • โ˜ ์ด๋ฏธ์ง€ ์ถœ์ฒ˜ - Josh Comeau

  1. (์„œ๋ฒ„) ์ฝ˜ํ…์ธ  ๋‹ค์šด๋กœ๋“œ ํ›„ HTML ์ƒ์„ฑ
  2. (ํด๋ผ์ด์–ธํŠธ) JS ๋ฒˆ๋“ค์„ ํฌํ•จํ•œ ๋ฆฌ์†Œ์Šค ๋‹ค์šด๋กœ๋“œ
    ===== ๋ ˆ์ด์•„์›ƒ ๋ฐ ์ฝ˜ํ…์ธ  ํ‘œ์‹œ | ์ธํ„ฐ๋ ‰์…˜ ๋ถˆ๊ฐ€ =====
  3. (ํด๋ผ์ด์–ธํŠธ) ํ•˜์ด๋“œ๋ ˆ์ด์…˜
    ===== ์ธํ„ฐ๋ ‰์…˜ ๊ฐ€๋Šฅ =====

 

SSR with Server Component, Streaming(Suspense)

UI๋ฅผ ์ฒญํฌ ๋‹จ์œ„๋กœ ๋‚˜๋ˆ ์„œ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’๊ฑฐ๋‚˜ ๋ฐ์ดํ„ฐ์— ์˜์กดํ•˜์ง€ ์•Š๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋จผ์ € ์ „์†ก(์ŠคํŠธ๋ฆฌ๋ฐ), ๊ธฐ์กด SSR๋ณด๋‹ค ๋” ๋น ๋ฅด๊ฒŒ ์ฝ˜ํ…์ธ ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค. ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ŠคํŠธ๋ฆฌ๋ฐ๋˜๋Š” ๋™์•ˆ ํด๋ผ์ด์–ธํŠธ์—์„  ํ•˜์ด๋“œ๋ ˆ์ด์…˜์ด ๋™์‹œ์— ์ง„ํ–‰๋ผ์„œ ๋” ๋น ๋ฅธ ํ•˜์ด๋“œ๋ ˆ์ด์…˜ ๊ฐ€๋Šฅ → ์ดˆ๊ธฐ ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ์‹œ๊ฐ„(TTI)์„ ๋‹จ์ถ•ํ•  ์ˆ˜ ์žˆ๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.

 

SSR ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ์ŠคํŠธ๋ฆฌ๋ฐ ๋ Œ๋”๋ง ๊ณผ์ • โ˜ ์ด๋ฏธ์ง€ ์ถœ์ฒ˜ Josh Comeau

  1. (์„œ๋ฒ„) ๋ ˆ์ด์•„์›ƒ HTML ์ƒ์„ฑ ๋ฐ ์ฝ˜ํ…์ธ  ๋‹ค์šด๋กœ๋“œ
  2. (ํด๋ผ์ด์–ธํŠธ) JS ๋ฒˆ๋“ค์„ ํฌํ•จํ•œ ๋ฆฌ์†Œ์Šค ๋‹ค์šด๋กœ๋“œ
    ===== ๋ ˆ์ด์•„์›ƒ ํ‘œ์‹œ | ์ธํ„ฐ๋ ‰์…˜ ๋ถˆ๊ฐ€ =====
  3. (ํด๋ผ์ด์–ธํŠธ) ๋ถ€๋ถ„ ํ•˜์ด๋“œ๋ ˆ์ด์…˜
    ===== ๋ถ€๋ถ„ ์ธํ„ฐ๋ ‰์…˜ ๊ฐ€๋Šฅ =====
  4. (์„œ๋ฒ„) ์ฝ˜ํ…์ธ ๋ฅผ ํฌํ•จํ•œ HTML ์ƒ์„ฑ
  5. (ํด๋ผ์ด์–ธํŠธ) ์ฝ˜ํ…์ธ  HTML ๋‹ค์šด๋กœ๋“œ ๋ฐ ํ•˜์ด๋“œ๋ ˆ์ด์…˜
    ===== ์ „์ฒด ์ธํ„ฐ๋ ‰์…˜ ๊ฐ€๋Šฅ =====

 

 

๋ ˆํผ๋Ÿฐ์Šค


 


๊ธ€ ์ˆ˜์ •์‚ฌํ•ญ์€ ๋…ธ์…˜ ํŽ˜์ด์ง€์— ๊ฐ€์žฅ ๋น ๋ฅด๊ฒŒ ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค. ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•ด ์ฃผ์„ธ์š”
๋ฐ˜์‘ํ˜•