Caching

ν•™μŠ΅ν‚€μ›Œλ“œ

  • Router Cache

  • Full Route Cache

  • Request Memoization

  • Data Cache

πŸ“– μΊμ‹œ : 컴퓨터 κ³Όν•™μ—μ„œ λ°μ΄ν„°λ‚˜ 값을 미리 볡사해 놓은 μž„μ‹œ μž₯μ†Œ

πŸ“– 캐싱 : μ–΄λ–€ 데이터λ₯Ό ν•œλ²ˆμ— λ°›μ•„μ˜¨ 후에 κ·Έ 데이터λ₯Ό 뢈러온 μ €μž₯μ†Œλ³΄λ‹€ κ°€κΉŒμš΄ 곳에 μž„μ‹œλ‘œ μ €μž₯ν•˜μ—¬, ν•„μš”μ‹œ 더 λΉ λ₯΄κ²Œ λΆˆλŸ¬μ™€μ„œ μ‚¬μš©ν•˜λŠ” ν”„λ‘œμ„ΈμŠ€

Next.jsλŠ” μ„±λŠ₯을 ν–₯μƒμ‹œν‚€κ³  λΉ„μš©μ„ μ ˆκ°ν•˜κΈ° μœ„ν•΄ μ΅œλŒ€ν•œ μΊμ‹œν•œλ‹€. κ²½λ‘œλŠ” μ •μ μœΌλ‘œ λ Œλ”λ§ 되고, 데이터 μš”μ²­μ€ μΊμ‹œ λœλ‹€λŠ”κ²ƒμ„ μ˜λ―Έν•œλ‹€.

Caching

Router Cache

Next.jsμ—λŠ” μ‚¬μš©μž μ„Έμ…˜ λ™μ•ˆ κ°œλ³„ 경둜 μ„Έκ·Έλ¨ΌνŠΈλ‘œ λΆ„ν• λœ React Server Component Payload(RSC Payload)λ₯Ό μ €μž₯ν•˜λŠ” in-memoryλ₯Ό ν΄λΌμ΄μ–ΈνŠΈ μΈ‘, μΊμ‹œλ₯Ό μ˜λ―Έν•œλ‹€.

How the Router Cache Works

http://localhost:3000/aλΌλŠ” νŽ˜μ΄μ§€ μš”μ²­μ„ ν•˜λ©΄ Router CacheλŠ” ν•΄λ‹Ή νŽ˜μ΄μ§€μ˜ μΊμ‹œκΈ°λ‘μ„ ν™•μΈν•˜λ‹€. Miss둜 νŒλ‹¨ν•˜κ²Œ 되면 μΊμ‹œν•˜κΈ° μœ„ν•œ 절차λ₯Ό μ§„ν–‰ν•œλ‹€. http://localhost:3000/bλΌλŠ” νŽ˜μ΄μ§€λ₯Ό μš”μ²­ν•˜λ©΄ Router CacheλŠ” ν•΄λ‹Ή νŽ˜μ΄μ§€μ˜ μΊμ‹œκΈ°λ‘μ„ ν™•μΈν•˜κ³  Miss둜 νŒλ‹¨ν•˜κ²Œ 되면 μΊμ‹œν•˜κΈ° μœ„ν•œ 절차λ₯Ό μ§„ν–‰ν•œλ‹€. λ‹€μ‹œ http://localhost:3000/a λΌλŠ” νŽ˜μ΄μ§€λ₯Ό μš”μ²­ν•˜λ©΄ Router CacheλŠ” ν•΄λ‹Ή νŽ˜μ΄μ§€μ˜ μΊμ‹œκΈ°λ‘μ„ νŒλ‹¨ν•˜κ³ , 기둝이 μžˆλ‹€λ©΄(HIT) νŽ˜μ΄μ§€λ₯Ό λ‹€μ‹œ λ‘œλ“œ ν•˜μ§€ μ•Šκ³ , React와 λΈŒλΌμš°μ € μƒνƒœλ₯Ό μΊμ‹±ν•œ 컨텐츠λ₯Ό μ‚¬μš©μžμ—κ²Œ 보여쀀닀.

μ‚¬μš©μžκ°€ λΌμš°νŠΈκ°„μ„ μ΄λ™ν•˜λŠ” λ™μ•ˆ Next.jsκ°€ λ°©λ¬Έν•œ 라우트 μ„Έκ·Έλ¨ΌνŠΈλ₯Ό μΊμ‹œν•˜κ³ , μ‚¬μš©μžκ°€ 이동할 κ°€λŠ₯성이 μžˆλŠ” 경둜λ₯Ό 미리 κ°€μ Έμ˜΄μœΌλ‘œμ„œ μ‚¬μš©μžμ˜ λ„€λΉ„κ²Œμ΄μ…˜ κ²½ν—˜μ„ ν–₯μƒμ‹œν‚¨λ‹€.

⏰ Router Cache μ§€μ†μ‹œκ°„

μΊμ‹œλŠ” λΈŒλΌμš°μ €μ˜ μž„μ‹œ λ©”λͺ¨λ¦¬μ— μ €μž₯λœλ‹€. λΌμš°ν„° μΊμ‹œμ˜ μ§€μ†μ‹œκ°„μ„ κ²°μ •ν•˜λŠ” 두가지 μš”μ†ŒλŠ” λ‹€μŒκ³Ό κ°™λ‹€.

  • Session : μΊμ‹œλŠ” 탐색 μ „λ°˜μ— 걸쳐 μ§€μ†λœλ‹€. κ·ΈλŸ¬λ‚˜ μƒˆλ‘œκ³ μΉ¨ ν•˜λ©΄ μ§€μ›Œμ§„λ‹€.

  • μžλ™ λ¬΄νš¨ν™” κΈ°κ°„ : κ°œλ³„ μ„Έκ·Έλ¨ΌνŠΈμ˜ μΊμ‹œλŠ” νŠΉμ •μ‹œκ°„μ΄ μ§€λ‚˜λ©΄ μžλ™μœΌλ‘œ λ¬΄νš¨ν™” λœλ‹€. 이기간은 κ²½λ‘œκ°€ μ •μ μœΌλ‘œ λ™μ μœΌλ‘œ λ Œλ”λ§ λ˜λŠ”μ§€μ— 따라 달라진닀.

    • λ™μ μœΌλ‘œ λ Œλ”λ§ 된 경우 : 30초

    • μ •μ μœΌλ‘œ λ Œλ”λ§ 된 경우 : 5λΆ„

⚠️ κ°œλ³„ μ„Έκ·Έλ¨ΌνŠΈκ°€ λ§ˆμ§€λ§‰μœΌλ‘œ μ—‘μ„ΈμŠ€ λ˜κ±°λ‚˜ μƒμ„±λœ μ‹œκ°„λΆ€ν„° 영ν–₯을 λ°›λŠ”λ‹€.

πŸ‘©πŸ»β€πŸ’» 예제λ₯Ό 톡해 λΌμš°ν„° μΊμ‹œ μž‘λ™ 방식을 μ΄ν•΄λ³΄μž

app
β”œβ”€β”€ layout.tsx
β”œβ”€β”€ page.tsx
β”œβ”€β”€ about β†’ μ •μ κ²½λ‘œ
β”‚   └── page.tsx
└── blog
    └── [id] β†’ λ™μ κ²½λ‘œ
        └── page.tsx
// πŸ“‚ app/layout.tsx
export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode,
}>) {
  return (
    <html lang="en">
      <body className="p-10">
        <h1 className="text-3xl font-bold mb-4">RootLayout Component</h1>
        <p className="mt-4 text-lg font-bold mb-10">
          {new Date().toLocaleTimeString()}
        </p>
        <nav className="flex gap-10 mb-10">
          <Link className="text-lg text-blue-700 " href={'/'}>
            /
          </Link>
          <Link className="text-lg text-blue-700" href={'/about'}>
            /About
          </Link>
          <Link className="text-lg text-green-700" href={'/blog/1'}>
            /blog/1
          </Link>
          <Link className="text-lg text-green-700" href={'/blog/2'}>
            /blog/2
          </Link>
        </nav>
        {children}
      </body>
    </html>
  );
}

RootLayout.tsx νŒŒμΌμ—λŠ” <Link>μ»΄ν¬λ„ŒνŠΈλ₯Ό μ‚¬μš©ν•΄μ„œ κ²½λ‘œμ΄λ™μ΄ κ°€λŠ₯ν•˜λ„λ‘ μ§€μ •ν•΄λ‘μ—ˆλ‹€.

// κ°œλ³„μ„Έκ·Έλ¨ΌνŠΈ
// πŸ“‚ /about
// πŸ“‚ /blog/[id]
export default function page() {
  return (
    <section className="bg-gray-200 p-10">
      <h1 className="text-2xl font-bold">About page Component</h1>
      <p className="mt-4 text-lg font-bold">
        {new Date().toLocaleTimeString()}
      </p>
    </section>
  );
}

/about, /blog/:id μ •μ κ²½λ‘œμ™€ λ™μ κ²½λ‘œλ₯Ό μ§€μ •ν•œ νŽ˜μ΄μ§€λ₯Ό μƒμ„±ν•΄λ‘μ—ˆκ³ , ν•΄λ‹Ή νŽ˜μ΄μ§€κ°€ λ‘œλ“œλ˜λ©΄ ν˜„μž¬ μ‹œκ°„μ„ 좜λ ₯ν•˜λ„λ‘ κ΅¬ν˜„ν–ˆλ‹€.

적용된 ν™”λ©΄

πŸ§ͺ Router Cacheκ°€ μ μš©λ˜μ–΄, RootLayout의 μ»΄ν¬λ„ŒνŠΈμ— 적용된 μ‹œκ°„μ€ μΊμ‹±λ˜μ–΄ λ‹€λ₯Έ 경둜 μ΄λ™μ‹œ ν˜„μž¬ μ‹œκ°„μ„ λ³΄μ—¬μ£ΌλŠ”κ²Œ μ•„λ‹ˆλΌ, 첫 RootLayout의 μ»΄ν¬λ„ŒνŠΈ λ Œλ”λ§μ‹œ 좜λ ₯λ˜μ—ˆλ˜ μ‹œκ°„μ„ μœ μ§€ν•΄μ„œ 보여쀀닀.

Full Route Cache

  • Next.jsμ—μ„œ 라우트의 λ Œλ”λ§ κ²°κ³Όλ₯Ό μΊμ‹œν•˜μ—¬ μ„œλ²„μ—μ„œ ν΄λΌμ΄μ–ΈνŠΈλ‘œμ˜ 반볡적인 λ Œλ”λ§ μš”μ²­μ„ 쀄이고, νŽ˜μ΄μ§€ λ‘œλ“œ μ„±λŠ₯을 ν–₯μƒμ‹œν‚¨λ‹€.

Full Route Cache

βœ… Full Route Cache vs Route Cache 차이점

  • λΌμš°ν„°μΊμ‹œ : μ‚¬μš©μž μ„Έμ…˜ λ™μ•ˆ λΈŒλΌμš°μ €μ— React μ„œλ²„ κ΅¬μ„±μš”μ†Œ νŽ˜μ΄λ‘œλ“œλ₯Ό μž„μ‹œλ‘œ μ €μž₯ν•œλ‹€. 정적 및 λ™μ μœΌλ‘œ λ Œλ”λ§λœ 경둜 λͺ¨λ‘ μ μš©λœλ‹€.

  • 전체 경둜 μΊμ‹œ : μ—¬λŸ¬ μ‚¬μš©μž μš”μ²­μ— 걸쳐 μ„œλ²„μ—μ„œ React μ„œλ²„ κ΅¬μ„±μš”μ†Œ νŽ˜μ΄λ‘œλ“œμ™€ HTML을 μ§€μ†μ μœΌλ‘œ μ €μž₯ν•œλ‹€. λΉŒλ“œ λ˜λŠ” μž¬κ²€μ¦ 쀑에 μ •μ μœΌλ‘œ λ Œλ”λ§λœ 경둜만 μΊμ‹œν•œλ‹€.

⭐️ μ „μ²΄λΌμš°νŠΈμΊμ‹œ(Full Route Cache)λŠ” μ„œλ²„μΈ‘μ—μ„œ νŽ˜μ΄μ§€μ˜ HTMLλ Œλ”λ§ κ²°κ³Όλ₯Ό μΊμ‹œν•˜κ³ , λΌμš°ν„° μΊμ‹œ(Router Cache)λŠ” ν΄λΌμ΄μ–ΈνŠΈμΈ‘μ—μ„œ μ‚¬μš©μžκ°€ λ°©λ¬Έν•œ 경둜 μ„Έκ·Έλ¨ΌνŠΈλ₯Ό μΊμ‹œν•˜μ—¬ μ‚¬μš©μžμ˜ 경둜 이동을 더 λΉ λ₯΄κ²Œ λ§Œλ“ λ‹€.

Request Memoization

ReactλŠ” fetchAPIλ₯Ό ν™•μž₯ν•˜μ—¬ λ™μΌν•œ URLκ³Ό μ˜΅μ…˜μ„ κ°€μ§„ μš”μ²­μ„ μžλ™μœΌλ‘œ λ©”λͺ¨ν•œλ‹€. μ΄λŠ” React μ»΄ν¬λ„ŒνŠΈ 트리의 μ—¬λŸ¬ μœ„μΉ˜μ— λ™μΌν•œ 데이터에 λŒ€ν•œ κ°€μ Έμ˜€κΈ° ν•¨μˆ˜λ₯Ό ν•œλ²ˆλ§Œ μ‹€ν–‰ν•˜λ©΄μ„œ ν˜ΈμΆœν•  수 μžˆμŒμ„ μ˜λ―Έν•œλ‹€. React μ»΄ν¬λ„ŒνŠΈκ°€ λ Œλ”λ§λ˜λŠ” λ™μ•ˆμ—λ§Œ μΊμ‹œλœ 데이터λ₯Ό μ‚¬μš©ν•˜μ—¬ μ„±λŠ₯을 ν–₯μƒμ‹œν‚€κ³ , μ€‘λ³΅λœ μš”μ²­μ„ λ°©μ§€ν•˜κΈ° μœ„ν•΄ μ‚¬μš©λœλ‹€.

일반적으둜 νŽ˜μ΄μ§€λ₯Ό λ Œλ”λ§ν•  λ•Œ μ„œλ²„μ—μ„œ 데이터λ₯Ό 가져와야 ν•˜λŠ”λ°, 이λ₯Ό μ—¬λŸ¬ μ»΄ν¬λ„ŒνŠΈμ—μ„œ μ€‘λ³΅ν•΄μ„œ μš”μ²­ν•˜λŠ” 것은 λΉ„νš¨μœ¨μ μΌ 수 μžˆλ‹€. λ”°λΌμ„œ ν•œλ²ˆ μš”μ²­λœ 데이터λ₯Ό μΊμ‹œν•˜μ—¬ μ—¬λŸ¬ μ»΄ν¬λ„ŒνŠΈμ—μ„œ μž¬μ‚¬μš©ν•  수 있게 ν•œλ‹€.

How Request Memoization Works
  • route을 λ Œλ”λ§ν•˜λŠ” λ™μ•ˆ, 처음 νŠΉμ •ν•œ μš”μ²­μ΄ 호좜되면 κ·Έκ²ƒμ˜ κ²°κ³ΌλŠ” λ©”λͺ¨λ¦¬μ— μ €μž₯λ˜μ§€ μ•Šκ³  cacheλœλ‹€. MISS

  • ν•¨μˆ˜κ°€ μ‹€ν–‰λ˜κ³  μ™ΈλΆ€ μ†ŒμŠ€μ—μ„œ 데이터λ₯Ό 가져와 κ²°κ³Όκ°€ λ©”λͺ¨λ¦¬μ— μ €μž₯λœλ‹€.SET

  • λ™μΌν•œ λžœλ” κ²½λ‘œμ—μ„œ μš”μ²­μ˜ 후속 ν•¨μˆ˜ ν˜ΈμΆœμ€ μΊμ‹œκ°€ 되며 HIT(λ°μ΄ν„°λŠ” ν•¨μˆ˜λ₯΄ μ‹€ν–‰ν•˜μ§€ μ•Šκ³ ) λ©”λͺ¨λ¦¬μ—μ„œ λ°˜ν™˜λœλ‹€.

  • routeκ°€ λ Œλ”λ§ 되고, λ Œλ”λ§ νŒ¨μŠ€κ°€ μ™„λ£Œλ˜λ©΄ λ©”λͺ¨λ¦¬κ°€ 'μž¬μ„€μ •'되고, λͺ¨λ“  μš”μ²­ λ©”λͺ¨ ν•­λͺ©μ΄ μ§€μ›Œμ§„λ‹€.

    • 이전 μš”μ²­μ— λŒ€ν•œ μΊμ‹œλ₯Ό μœ μ§€ν•˜λŠ” 것은 λ©”λͺ¨λ¦¬λ₯Ό λ‚­λΉ„ν•˜κ³ , λΆˆν•„μš”ν•œ 데이터λ₯Ό μœ μ§€ν•˜λŠ” 것 일 수 μžˆλ‹€. 특히 React μ—μ„œλŠ” λ Œλ”λ§κ³Ό κ΄€λ ¨λœ μƒνƒœμ™€ 데이터λ₯Ό μ΅œμ‹  μƒνƒœλ‘œ μœ μ§€ν•˜λŠ” 것이 μ€‘μš”ν•˜λ‹€. λ”°λΌμ„œ λ‹€μŒ μš”μ²­μ— λŒ€ν•œ λ©”λͺ¨μ΄μ œμ΄μ…˜μ„ μœ„ν•΄ μƒˆλ‘œμš΄ 곡간을 ν™•λ³΄ν•œλ‹€.

πŸ—‘οΈ Request Memoization은 νŽ˜μ΄μ§€ λ Œλ”λ§μ„ μœ„ν•œ κ²ƒμ΄λ―€λ‘œ νŽ˜μ΄μ§€κ°€ λ Œλ”λ§ 된 ν›„μ—λŠ” λΉ„μ›Œμ€€λ‹€

πŸ“Œ 참고사항

  • Request Memoization은 fetch μš”μ²­μ˜ GET λ©”μ„œλ“œμ—λ§Œ μ μš©λœλ‹€.

  • Request Memoization은 React ꡬ성 μš”μ†Œ 트리(React Component tree)μ—λ§Œ μ μš©λœλ‹€.

    • 메타데이터 생성, 정적 λ§€κ°œλ³€μˆ˜, λ ˆμ΄μ•„μ›ƒ, νŽ˜μ΄μ§€ 및 기타 μ„œλ²„ κ΅¬μ„±μš”μ†Œ μƒμ„±μ—μ„œ μš”μ²­μ„ κ°€μ Έμ˜€λŠ” 데 적용

    • Route Handler의 κ°€μ Έμ˜€κΈ° μš”μ²­μ€ React ꡬ성 μš”μ†Œ 트리의 일뢀가 μ•„λ‹ˆλ―€λ‘œ μ μš©λ˜μ§€ μ•ŠλŠ”λ‹€.

πŸ‘©πŸ»β€πŸ’» 예제λ₯Ό 톡해 Request Memoization μž‘λ™ 방식을 μ΄ν•΄λ³΄μž

// πŸ“‚ /about
export default async function page() {
  const posts = await (await fetch('http://localhost:4000/posts')).json();
  const blogs = await (await fetch('http://localhost:4000/blogs')).json();
  return (
    <section className="bg-gray-200 p-10">
      <h1 className="text-2xl font-bold">About page Component</h1>
      <p className="mt-4 text-lg font-bold">
        {new Date().toLocaleTimeString()}
      </p>
      <p className="mt-4 text-lg font-bold">Posts</p>
      <pre>{JSON.stringify(posts, null, 2)}</pre>
      <p className="mt-4 text-lg font-bold">Blogs</p>
      <pre>{JSON.stringify(blogs, null, 2)}</pre>
    </section>
  );
}

/about νŽ˜μ΄μ§€λŠ” fetch APIλ₯Ό λ‘λ²ˆ μš”μ²­ν•œλ‹€. νŽ˜μ΄μ§€κ°€ λ Œλ”λ§ λ˜λ©΄μ„œ http://localhost:4000/posts μš”μ²­ Call은 /νŽ˜μ΄μ§€μ—μ„œ λ Œλ”λ§μ‹œ λ©”λͺ¨μ΄μ œμ΄μ…˜ λ˜μ–΄ μ„œλ²„λ‘œ λΆ€ν„° μš”μ²­ν•˜μ§€ μ•Šκ³ , http://localhost:4000/blogs API Call을 μš”μ²­ν•΄μ„œ λ Œλ”λ§ν•œ 화면을 보여쀀닀.

Data Cache

Next.jsμ—μ„œλŠ” λ“€μ–΄μ˜€λŠ” μ„œλ²„ μš”μ²­ 및 배포 μ „λ°˜μ— 걸쳐 데이터 κ°€μ Έμ˜€κΈ° κ²°κ³Όλ₯Ό μœ μ§€ν•˜λŠ” λ‚΄μž₯ 데이터 μΊμ‹œκ°€ μžˆλ‹€. Next.jsκ°€ κΈ°λ³Έ fetchAPIλ₯Ό ν™•μž₯ν•˜μ—¬ μ„œλ²„μ˜ 각 μš”μ²­μ΄ 자체 영ꡬ 캐싱 의미λ₯Ό μ„€μ •ν•  수 μžˆλ„λ‘ ν•˜κΈ° λ•Œλ¬Έμ— κ°€λŠ₯ν•˜λ‹€.

fetch μš”μ²­μ„ 받은 κ²°κ³Ό(Data)값을 μΊμ‹œ μ²˜λ¦¬ν•˜λŠ”λ°, μž¬κ²€μ¦ν•˜κ±°λ‚˜ μ„ νƒν•΄μ œ ν•˜μ§€ μ•ŠλŠ” ν•œ λ“€μ–΄μ˜€λŠ” μš”μ²­ 및 배포 μ „λ°˜μ— 걸쳐 μ§€μ†λœλ‹€.

How the Data Cache Works
  • 처음 λ Œλ”λ§ 쀑에 fetch μš”μ²­μ΄ 호좜되면, Next.jsλŠ” μΊμ‹œλœ 응닡을 ν™•μΈν•˜κΈ° 데이터 μΊμ‹œλ₯Ό ν™•μΈν•œλ‹€.

  • μΊμ‹œλœ 응닡이 발견되면 μ¦‰μ‹œ λ°˜ν™˜λ˜κ³ , λ©”λͺ¨μ΄μ œμ΄μ…˜λœλ‹€. μΊμ‹œλœ 응닡이 λ°œκ²¬λ˜μ§€ μ•ŠμœΌλ©΄ 데이터 μ†ŒμŠ€λ‘œ μš”μ²­μ΄ 이루어지고, κ²°κ³Όκ°€ 데이터 μΊμ‹œμ— μ €μž₯되고 λ©”λͺ¨μ΄μ œμ΄μ…˜ λœλ‹€.

  • μΊμ‹œλ˜μ§€ μ•Šμ€ λ°μ΄ν„°μ˜ 경우(예: { cache: 'no-store' }), 항상 데이터 μ†ŒμŠ€μ—μ„œ κ²°κ³Όλ₯Ό 가져와 λ©”λͺ¨μ΄μ œμ΄μ…˜λœλ‹€.

  • 데이터가 μΊμ‹œλ˜λ“ ,μΊμ‹œλ˜μ§€ μ•Šλ“  관계없이 μš”μ²­μ€ React λ Œλ” 패슀 쀑에 λ™μΌν•œ 데이터에 λŒ€ν•œ 쀑볡을 ν”Όν•˜κΈ° μœ„ν•΄ 항상 λ©”λͺ¨μ΄μ œμ΄μ…˜ ν•œλ‹€.

βœ… Request Memoization vs Data Cache 차이점

  • 지속성

    • Request Memoization : μš”μ²­μ˜ 수λͺ… λ™μ•ˆλ§Œ μ§€μ†λœλ‹€. ν•œλ²ˆμ˜ μš”μ²­μ—μ„œ λ‹€μŒμš”μ²­μœΌλ‘œμ˜ λ©”λͺ¨μ΄μ œμ΄μ…˜ λ°μ΄ν„°λŠ” μœ μ§€ λ˜μ§€ μ•ŠλŠ”λ‹€.

    • Data Cache : μˆ˜μ‹  μš”μ²­ 및 배포λ₯Ό 거쳐도 μ§€μ†λœλ‹€. 즉, 이전에 μΊμ‹œλœ λ°μ΄ν„°λŠ” μ—¬λ € μš”μ²­ 및 μ„œλ²„ 배포간에 μœ μ§€λœλ‹€.

🧐 ν•˜λ‚˜μ˜ μš”μ²­ λ™μ•ˆ μœ νš¨ν•œ Request Memoization λ‹€λ₯΄κ²Œ Data CacheλŠ” μΌμ •μ‹œκ°„ λ™μ•ˆ μ›Ή μ„œλ²„λ‘œ λ“€μ–΄μ˜€λŠ” λͺ¨λ“  μš”μ²­μ— λŒ€ν•΄ λ™μž‘ν•œλ‹€. λ§Œμ•½ next.revalidate λ₯Ό 1초둜 μ„€μ •ν–ˆλ‹€λ©΄, 1μ΄ˆμ— 1000λͺ…μ˜ μ‚¬μš©μžκ°€ 접속해도 μ‹€μ œ API μš”μ²­μ€ 1회 μ „μ†‘λœλ‹€.

  • λ„€νŠΈμ›Œν¬ ꡐ차점

    • Request Memoization : λ™μΌν•œ λ Œλ”μΌ 패슀(λ Œλ”λ§ν•˜λŠ” 쀑)λ‚΄μ˜ 쀑볡 μš”μ²­ 수λ₯Ό 쀄일 수 μžˆλ‹€.

    • Data Cache : 원본 데이터 μ†ŒμŠ€μ— λŒ€ν•œ μš”μ²­μˆ˜λ₯Ό 쀄일 수 μžˆλ‹€.

πŸ€” μ΄ν•΄λ³΄μžλ©΄, Request MemoizationλŠ” ν•˜λ‚˜μ˜ API Call에 λŒ€ν•œ 쀑볡 μš”μ²­μˆ˜λ₯Ό 쀄일 수 있고, Data CacheλŠ” μ—¬λŸ¬ API Call을 κ΄€λ¦¬ν•˜λŠ”λ°, 각각의 API Call에 λŒ€ν•œ μš”μ²­μˆ˜λ₯Ό 쀄일 수 μžˆλ‹€λŠ” 말둜 μš°μ„  μ΄ν•΄ν–ˆλ‹€.

βš–οΈ μž¬κ²€μ¦

  • μ‹œκ°„ 기반 μž¬κ²€μ¦ : μΌμ •μ‹œκ°„μ΄ μ§€λ‚œ ν›„ μƒˆλ‘œμš΄ μš”μ²­μ΄ λ°œμƒν•œ ν›„ 데이터λ₯Ό μž¬κ²€μ¦

fetch('https://...', { next: { revalidate: 3600 } });
How Time-based Revalidation Works

🚨 revalidate μ‹œκ°„μ΄ μ§€λ‚˜λ”λΌλ„ 첫 μš”μ²­μ€ μΊμ‹±λœ 값을 (STALE μƒνƒœμ—¬λ„) λ°˜ν™˜ν•œλ‹€λŠ” 것이닀. λ°˜ν™˜ ν›„ λ°±κ·ΈλΌμš΄λ“œμ—μ„œ APIλ₯Ό ν˜ΈμΆœν•΄μ„œ 값을 μ—…λ°μ΄νŠΈν•˜λŠ”λ°, 개발자 μ˜λ„μ™€ λ‹€λ₯΄κ²Œ λ™μž‘ν•  수 있기 λ•Œλ¬Έμ— μΊμ‹œλ₯Ό μ μš©ν•  λ•Œ μ£Όμ˜κ°€ ν•„μš”ν•˜λ‹€.

  • μ£Όλ¬Έν˜• μž¬κ²€μ¦ : 이벀트λ₯Ό 기반으둜 데이터λ₯Ό μž¬κ²€μ¦

    • ν•„μš”μ— 따라 경둜( revalidatePath) λ˜λŠ” μΊμ‹œ νƒœκ·Έ( revalidateTag)λ₯Ό 톡해 λ°μ΄ν„°μ˜ μœ νš¨μ„±μ„ μž¬κ²€μ¦

fetch('https://...', { next: { tags: ['a'] } });
How On-Demand Revalidation Works

Optiong Out

κ°œλ³„ 데이터 fetch의 경우, μΊμ‹œ μ˜΅μ…˜μ„ no-store둜 μ„€μ •ν•˜μ—¬ μΊμ‹±μ—μ„œ μ œμ™Έν•  수 μžˆλ‹€.

// Opt out of caching for an individual `fetch` request
fetch(`https://...`, { cache: 'no-store' });

πŸ‘©πŸ»β€πŸ’» 정리

Next.jsλŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ μ„±λŠ₯을 ν–₯μƒν•˜κ³  λΉ„μš©μ„ μ ˆκ°ν•˜κΈ° μœ„ν•΄ λ Œλ”λ§ μž‘μ—…κ³Ό 데이터 μš”μ²­μ„ μΊμ‹±ν•©λ‹ˆλ‹€. Next.js의 캐싱 λ©”μ»€λ‹ˆμ¦˜μ€ 4κ°€μ§€λ‘œ 이루어져 μžˆμŠ΅λ‹ˆλ‹€.

  • 첫 번째 Router CacheλŠ” ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œ μ‚¬μš©μžκ°€ νŽ˜μ΄μ§€λ₯Ό μ΄λ™ν•˜λŠ” λ™μ•ˆ λ°©λ¬Έν•œ νŽ˜μ΄μ§€(라우트 μ„Έκ·Έλ¨ΌνŠΈ)λ₯Ό μΊμ‹œν•˜κ³ , μ‚¬μš©μžκ°€ 이동할 κ°€λŠ₯성이 μžˆλŠ” 경둜λ₯Ό 미리 κ°€μ Έμ˜΄μœΌλ‘œμ¨ μ‚¬μš©μžμ˜ λ‚΄λΉ„κ²Œμ΄μ…˜ κ²½ν—˜μ„ ν–₯μƒν•©λ‹ˆλ‹€. Router CacheλŠ” νŽ˜μ΄μ§€κ°€ μƒˆλ‘œκ³ μΉ¨ λ˜κ±°λ‚˜, 정적 λ˜λŠ” 동적 κ²½λ‘œμ— μ˜ν•΄ μ§€μ •λ˜λŠ” νŠΉμ • μ‹œκ°„μ΄ μ§€λ‚˜λ©΄ μžλ™μœΌλ‘œ 캐싱 처리λ₯Ό λ¬΄νš¨ν™” ν•©λ‹ˆλ‹€.

  • 두 번째 Full Route CacheλŠ” λΉŒλ“œμ‹œ μ •μ μœΌλ‘œ λ Œλ”λ§ 된 경둜만 HTML λ Œλ”λ§μ˜ κ²°κ³Όλ₯Ό μΊμ‹œ ν•˜μ—¬ μ„œλ²„μ—μ„œ ν΄λΌμ΄μ–ΈνŠΈλ‘œμ˜ 반볡적인 λ Œλ”λ§ μš”μ²­μ„ 쀄이고 νŽ˜μ΄μ§€ λ‘œλ“œ μ„±λŠ₯을 ν–₯μƒν•©λ‹ˆλ‹€.

  • μ„Έ 번째 Request Memoization은 ν•˜λ‚˜μ˜ νŽ˜μ΄μ§€κ°€ λ Œλ”λ§ν•˜λŠ” λ™μ•ˆ λ™μΌν•œ URLκ³Ό μ˜΅μ…˜μ„ κ°€μ§„ μš”μ²­μ„ μžλ™μœΌλ‘œ λ©”λͺ¨μ΄μ œμ΄μ…˜ ν•©λ‹ˆλ‹€. λ™μΌν•œ 데이터에 λŒ€ν•œ μš”μ²­ ν•¨μˆ˜λ₯Ό μ—¬λŸ¬ κ³³μ—μ„œ ν˜ΈμΆœν•΄μ•Ό ν•  λ•Œ ν•œ 번만 μ‹€ν–‰ν•˜μ—¬ 결괏값을 μΊμ‹±ν•˜μ—¬ μ€‘λ³΅λœ μš”μ²­μ„ λ°©μ§€ν•˜κΈ° μœ„ν•΄ μ‚¬μš©λ©λ‹ˆλ‹€. fetch μš”μ²­μ˜ GET λ©”μ„œλ“œμ—μ„œλ§Œ μ μš©λ©λ‹ˆλ‹€.

  • λ„€ 번째 Data CacheλŠ” fetch APIλ₯Ό ν™•μž₯ν•˜μ—¬ μ„œλ²„μ˜ 각 μš”μ²­ 받은 결괏값(데이터)을 μ„œλ²„ μš”μ²­ 및 배포 간에 μœ μ§€ν•˜λŠ” λ‚΄μž₯된 μΊμ‹œμž…λ‹ˆλ‹€. μž¬κ²€μ¦ν•˜κ±°λ‚˜ μ˜΅μ…˜μ„ λ³€κ²½ν•˜μ§€ μ•ŠλŠ” ν•œ λ“€μ–΄μ˜€λŠ” μš”μ²­ 및 배포 μ „λ°˜μ— 걸쳐 영ꡬ적으둜 μš”μ²­λ°›μ€ 결괏값이 μ§€μ†λ©λ‹ˆλ‹€. μ μ ˆν•˜κ²Œ 캐싱 처리λ₯Ό λ¬΄νš¨ν™” ν•΄μ•Ό ν•©λ‹ˆλ‹€. 일정 μ‹œκ°„μ΄ μ§€λ‚œ ν›„ μƒˆλ‘œμš΄ μš”μ²­μ΄ λ°œμƒν•˜λ©΄ 데이터λ₯Ό μž¬κ²€μ¦ν•˜λŠ” μ‹œκ°„ 기반으둜 κ²€μ¦ν•˜λŠ” 방식이 있고, ν•„μš”μ— 따라 경둜(revalidatePath) λ˜λŠ” νƒœκ·Έ(revalidateTag)λ₯Ό μ΄λ²€νŠΈμ™€ μ—°κ²°ν•˜μ—¬ λ°μ΄ν„°μ˜ μœ νš¨μ„±μ„ κ²€μ¦ν•˜λŠ” 방식이 μžˆμŠ΅λ‹ˆλ‹€. κ°œλ³„μ μΈ μš”μ²­μ˜ κ²½μš°μ—λŠ” μΊμ‹œ μ˜΅μ…˜μ„ no-store(예: { cache: 'no-store' })둜 μ„€μ •ν•˜μ—¬ μΊμ‹±μ—μ„œ μ œμ™Έν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

πŸ”— μ°Έκ³ 

Last updated