Next.js cache

j_wisdom_hยท2024๋…„ 2์›” 26์ผ
1

Next.js ํ”„๋กœ์ ํŠธ

๋ชฉ๋ก ๋ณด๊ธฐ
6/8

๐Ÿ’ก ์บ์‹ฑ ๋Œ€์ƒ : ๋ Œ๋”๋ง ์ž‘์—…, ๋ฐ์ดํ„ฐ ์š”์ฒญ
๐Ÿ’ก ๋ชฉ์ : ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ, ๋น„์šฉ ์ ˆ๊ฐ

Overview

  • ์บ์‹œ : ์ปดํ“จํ„ฐ ๊ณผํ•™์—์„œ ๋ฐ์ดํ„ฐ๋‚˜ ๊ฐ’์„ ๋ฏธ๋ฆฌ ๋ณต์‚ฌํ•ด ๋†“๋Š” ์ž„์‹œ ์žฅ์†Œ
  • ์บ์‹ฑ : ํŒŒ์ผ ๋ณต์‚ฌ๋ณธ์„ ์บ์‹œ ๋˜๋Š” ์ž„์‹œ ์ €์žฅ ์œ„์น˜์— ์ €์žฅํ•˜์—ฌ ๋ณด๋‹ค ๋น ๋ฅด๊ฒŒ ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ํ”„๋กœ์„ธ์Šค

By default, Next.js will cache as much as possible to improve performance and reduce cost. This means routes areย statically renderedย and data requests areย cachedย unless you opt out.

Next.js์˜ ์บ์‹œ๋Š” ์„ฑ๋Šฅํ–ฅ์ƒ๊ณผ ๋น„์šฉ ์ ˆ๊ฐ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•œ๋‹ค. ์ด๊ฒƒ์€ ์˜๋ฏธ๋Š” ๊ฒฝ๋กœ๋Š”ย ์ •์ ์œผ๋กœ ๋ Œ๋”๋ง๋˜๊ณ ย ๋ฐ์ดํ„ฐ ์š”์ฒญ์€ย ์บ์‹œ ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

๋งค์ปค๋‹ˆ์ฆ˜WhatWherePurposeDuration
https://nextjs.org/docs/app/building-your-application/caching#request-memoizationํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜ ๊ฐ’serverReact ๊ตฌ์„ฑ ์š”์†Œ ํŠธ๋ฆฌ์—์„œ ๋ฐ์ดํ„ฐ ์žฌ์‚ฌ์šฉ์š”์ฒญ๋ณ„ ์ˆ˜๋ช… ์ฃผ๊ธฐ
https://nextjs.org/docs/app/building-your-application/caching#data-cache๋ฐ์ดํ„ฐserver์‚ฌ์šฉ์ž ์š”์ฒญ ๋ฐ ๋ฐฐํฌ ์ „๋ฐ˜์— ๊ฑธ์ณ ๋ฐ์ดํ„ฐ ์ €์žฅ์ง€์†์ (์žฌ๊ฒ€์ฆ ๊ฐ€๋Šฅ)
https://nextjs.org/docs/app/building-your-application/caching#full-route-cacheHTML ๋ฐ RSC ํŽ˜์ด๋กœ๋“œserver๋ Œ๋”๋ง ๋น„์šฉ ์ ˆ๊ฐ ๋ฐ ์„ฑ๋Šฅ ํ–ฅ์ƒ์ง€์†์ (์žฌ๊ฒ€์ฆ ๊ฐ€๋Šฅ)
https://nextjs.org/docs/app/building-your-application/caching#router-cacheRSC ํŽ˜์ด๋กœ๋“œclientํƒ์ƒ‰ ์‹œ ์„œ๋ฒ„ ์š”์ฒญ ์ค„์ด๊ธฐ์‚ฌ์šฉ์ž ์„ธ์…˜ ๋˜๋Š” ์‹œ๊ฐ„ ๊ธฐ๋ฐ˜

1. Request Memoization

React๋Š”ย fetchAPI๋ฅผ(https://nextjs.org/docs/app/building-your-application/caching#fetch)ย ํ™•์žฅํ•˜์—ฌ ๋™์ผํ•œ URL๊ณผ ์˜ต์…˜์„ ๊ฐ€์ง„ ์š”์ฒญ์„ย ์ž๋™์œผ๋กœย ๋ฉ”๋ชจํ•œ๋‹ค.ย ์ด๋Š” React ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ์˜ ์—ฌ๋Ÿฌ ์œ„์น˜์—์„œ ๋™์ผํ•œ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ๊ฐ€์ ธ์˜ค๊ธฐ ํ•จ์ˆ˜๋ฅผ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰ํ•˜๋ฉด์„œ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธํ•œ๋‹ค.

  • ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ : ํŽ˜์ด์ง€ ๋ Œ๋”๋ง, function return, server

React ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋˜๋Š” ๋™์•ˆ์—๋งŒ ์บ์‹œ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๊ณ , ์ค‘๋ณต๋œ ์š”์ฒญ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ’ก ์ฃผ์š” ๋ชฉ์ 
์ผ๋ฐ˜์ ์œผ๋กœ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•  ๋•Œ ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์•ผ ํ•˜๋Š”๋ฐ, ์ด๋ฅผ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ค‘๋ณตํ•ด์„œ ์š”์ฒญํ•˜๋Š” ๊ฒƒ์€ ๋น„ํšจ์œจ์ ์ผ ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ•œ ๋ฒˆ ์š”์ฒญ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์บ์‹œํ•˜์—ฌ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒํ•œ๋‹ค.
๐Ÿ’ก The fetch function is automatically memoized and the result is cached.

(์ฐธ๊ณ ) Request Memoization๋Š” next.js๊ฐ€ ์•„๋‹Œ react์˜ ๊ธฐ๋Šฅ์ด๋‹ค.

  • route์„ ๋ Œ๋”๋งํ•˜๋Š” ๋™์•ˆ, ์ฒ˜์Œ ํŠน์ •ํ•œ ์š”์ฒญ์ด ํ˜ธ์ถœ๋˜๋ฉด ๊ทธ๊ฒƒ์˜ ๊ฒฐ๊ณผ๋Š” ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ๋˜์ง€ ์•Š๊ณ  cache๋œ๋‹ค. MISS
  • ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๊ณ , ์™ธ๋ถ€ ์†Œ์Šค์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ๊ทธ ๊ฒฐ๊ณผ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ๋œ๋‹ค. SET
  • ๋™์ผํ•œ ๋ Œ๋” ๊ฒฝ๋กœ์—์„œ ์š”์ฒญ์˜ ํ›„์† ํ•จ์ˆ˜ ํ˜ธ์ถœ์€ ์บ์‹œ๊ฐ€ ๋˜๋ฉฐย HIT( ๋ฐ์ดํ„ฐ๋Š” ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ  ๋ฉ”๋ชจ๋ฆฌ์—์„œ ๋ฐ˜ํ™˜๋œ๋‹ค.
  • route๊ฐ€ ๋ Œ๋”๋ง๋˜๊ณ  ๋ Œ๋”๋ง ํŒจ์Šค๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ "์žฌ์„ค์ •"๋˜๊ณ  ๋ชจ๋“  ์š”์ฒญ ๋ฉ”๋ชจ ํ•ญ๋ชฉ์ด ์ง€์›Œ์ง„๋‹ค.
    • why? ์ด์ „ ์š”์ฒญ์— ๋Œ€ํ•œ ์บ์‹œ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋‚ญ๋น„ํ•˜๊ณ , ๋ถˆํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ผ ์ˆ˜ ์žˆ๋‹ค. ํŠนํžˆ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ๋ Œ๋”๋ง๊ณผ ๊ด€๋ จ๋œ ์ƒํƒœ์™€ ๋ฐ์ดํ„ฐ๋ฅผ ์ตœ์‹  ์ƒํƒœ๋กœ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค. ๋”ฐ๋ผ์„œ ๋‹ค์Œ ์š”์ฒญ์— ๋Œ€ํ•œ ๋ฉ”๋ชจ์ด์ œ์ด์…˜์„ ์œ„ํ•ด ์ƒˆ๋กœ์šด ๊ณต๊ฐ„์„ ํ™•๋ณดํ•œ๋‹ค. ์ด๊ฒƒ์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ์™€ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ์œ„ํ•œ ์ผ๋ฐ˜์ ์ธ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜์ด๋‹ค. ( = Request Memoization์€ ํŽ˜์ด์ง€ ๋ Œ๋”๋ง์„ ์œ„ํ•œ ๊ฒƒ์ด๋ฏ€๋กœ ํŽ˜์ด์ง€๊ฐ€ ๋ Œ๋”๋ง ๋œ ํ›„์—๋Š” ๋น„์›Œ์ค€๋‹ค)

๐Ÿ’ก route : ํŠน์ • URL์— ํ•ด๋‹นํ•˜๋Š” ํŽ˜์ด์ง€ ๋˜๋Š” ๊ฒฝ๋กœ
ex) /about
๐Ÿ’ก redering pass : ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๊ณผ์ •. ๋ผ์šฐํŠธ ๋งค์นญ, ๋ Œ๋”๋ง, ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ ๋“ฑ ๊ณผ์ •์ด ํฌํ•จ๋œ๋‹ค.

  • Memoization์€ fetch ์š”์ฒญ์˜ GET ๋ฉ”์„œ๋“œ์—๋งŒ ์ ์šฉ๋œ๋‹ค.
  • Memoization์€ React ๊ตฌ์„ฑ ์š”์†Œ ํŠธ๋ฆฌ์—๋งŒ ์ ์šฉ๋œ๋‹ค.

2. Data Cache

Next.js์—๋Š” ๋‚ด์žฅ๋œ ๋ฐ์ดํ„ฐ ์บ์‹œ๊ฐ€ ์žˆ๋‹ค. ์ด ์บ์‹œ๋Š” ์„œ๋ฒ„ ์š”์ฒญ ๋ฐ ๋ฐฐํฌ๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ์˜ ๊ฒฐ๊ณผ๋ฅผ ์œ ์ง€ํ•œ๋‹ค.

Next.js extends the nativeย fetchย API to allow each request on the server to set its own persistent caching semantics.

  • ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ : revalidate , server

  • ์ฒ˜์Œ ๋ Œ๋”๋ง ์ค‘์— fetch ์š”์ฒญ์ด ํ˜ธ์ถœ๋˜๋ฉด, Next.js๋Š” ์บ์‹œ๋œ ์‘๋‹ต์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ์ดํ„ฐ ์บ์‹œ๋ฅผ ํ™•์ธํ•œ๋‹ค.

  • ์บ์‹œ๋œ ์‘๋‹ต์ด ๋ฐœ๊ฒฌ๋˜๋ฉด ์ฆ‰์‹œ ๋ฐ˜ํ™˜๋˜๊ณ  ๋ฉ”๋ชจ์ด์ œ์ด์…˜๋œ๋‹ค. ์บ์‹œ๋œ ์‘๋‹ต์ด ๋ฐœ๊ฒฌ๋˜์ง€ ์•Š์œผ๋ฉด ๋ฐ์ดํ„ฐ ์†Œ์Šค๋กœ ์š”์ฒญ์ด ์ด๋ฃจ์–ด์ง€๊ณ , ๊ฒฐ๊ณผ๊ฐ€ ๋ฐ์ดํ„ฐ ์บ์‹œ์— ์ €์žฅ๋˜๊ณ  ๋ฉ”๋ชจ์ด์ œ์ด์…˜๋œ๋‹ค.

  • ์บ์‹œ๋˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ์˜ ๊ฒฝ์šฐ(์˜ˆ: { cache: 'no-store' }), ํ•ญ์ƒ ๋ฐ์ดํ„ฐ ์†Œ์Šค์—์„œ ๊ฒฐ๊ณผ๊ฐ€ ๊ฐ€์ ธ์™€์ง€๊ณ  ๋ฉ”๋ชจ์ด์ œ์ด์…˜๋œ๋‹ค. ๋ฐ์ดํ„ฐ๊ฐ€ ์บ์‹œ๋˜์—ˆ๋“  ์บ์‹œ๋˜์ง€ ์•Š์•˜๋“ , ์š”์ฒญ์€ ํ•ญ์ƒ ๋ฉ”๋ชจ์ด์ œ์ด์…˜๋˜์–ด React ๋ Œ๋”๋ง ํŒจ์Šค ์ค‘์— ๋™์ผํ•œ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์ค‘๋ณต ์š”์ฒญ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ํ•œ๋‹ค.

  • Differences between the Data Cache and Request Memoization

    1. ์ง€์†์„ฑ (Persistence):

      • ๋ฉ”๋ชจ์ด์ œ์ด์…˜: ์š”์ฒญ์˜ ์ˆ˜๋ช… ๋™์•ˆ๋งŒ ์ง€์†๋œ๋‹ค. ํ•œ ๋ฒˆ์˜ ์š”์ฒญ์—์„œ ๋‹ค์Œ ์š”์ฒญ์œผ๋กœ์˜ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ ๋ฐ์ดํ„ฐ๋Š” ์œ ์ง€๋˜์ง€ ์•Š๋Š”๋‹ค.
      • ๋ฐ์ดํ„ฐ ์บ์‹œ: ์ˆ˜์‹  ์š”์ฒญ ๋ฐ ๋ฐฐํฌ๋ฅผ ๊ฑฐ์ณ๋„ ์ง€์†๋œ๋‹ค. ์ฆ‰, ์ด์ „์— ์บ์‹œ๋œ ๋ฐ์ดํ„ฐ๋Š” ์—ฌ๋Ÿฌ ์š”์ฒญ ๋ฐ ์„œ๋ฒ„ ๋ฐฐํฌ ๊ฐ„์— ์œ ์ง€๋œ๋‹ค.
    2. ๋„คํŠธ์›Œํฌ ๊ต์ฐจ์  (Network Boundary):

      • ๋ฉ”๋ชจ์ด์ œ์ด์…˜: ๋ Œ๋”๋ง ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ ์บ์‹œ ์„œ๋ฒ„(์˜ˆ: CDN ๋˜๋Š” Edge Network) ๋˜๋Š” ๋ฐ์ดํ„ฐ ์†Œ์Šค(์˜ˆ: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋˜๋Š” CMS)๋กœ ๋„คํŠธ์›Œํฌ ๊ฒฝ๊ณ„๋ฅผ ๊ฑด๋„ˆ๊ฐ€์•ผ ํ•˜๋Š” ๋™์ผํ•œ ๋ Œ๋”๋ง ํŒจ์Šค ๋‚ด์˜ ์ค‘๋ณต ์š”์ฒญ ์ˆ˜๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.
      • ๋ฐ์ดํ„ฐ ์บ์‹œ: ์›๋ณธ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋กœ์˜ ์š”์ฒญ ์ˆ˜๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, ๋” ๋งŽ์€ ์š”์ฒญ์„ ๋ฐ์ดํ„ฐ ์บ์‹œ๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•  ์ˆ˜ ์žˆ์–ด์„œ ์›๋ณธ ๋ฐ์ดํ„ฐ ์†Œ์Šค์— ๋Œ€ํ•œ ์š”์ฒญ ์ˆ˜๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

      ๐Ÿ’ก ๋„คํŠธ์›Œํฌ ๊ต์ฐจ์  : ๋ฐ์ดํ„ฐ๊ฐ€ ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด ์ด๋™ํ•˜๋Š” ๋™์•ˆ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฒฝ์œ ํ•˜๋Š” ์ง€์ 

      • ๋ฉ”๋ชจ์ด์ œ์ด์…˜ ๋„คํŠธ์›Œํฌ ๊ต์ฐจ์  : ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ๊ฐ„์˜ ํ†ต์‹  ๊ฒฝ๋กœ
      • ๋ฐ์ดํ„ฐ ์บ์‹œ ๋„คํŠธ์›Œํฌ ๊ต์ฐจ์ : ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ๊ฐ„์˜ ํ†ต์‹  ๊ฒฝ๋กœ
  • ๋ฐ์ดํ„ฐ ์บ์‹œ๋Š” ์žฌ๊ฒ€์ฆํ•˜๊ฑฐ๋‚˜ ์„ ํƒ ํ•ด์ œํ•˜์ง€ ์•Š๋Š” ํ•œ ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ ๋ฐ ๋ฐฐํฌ ์ „๋ฐ˜์— ๊ฑธ์ณ ์ง€์†๋œ๋‹ค.

  • ์บ์‹œ๋œ ๋ฐ์ดํ„ฐ๋Š” ๋‹ค์Œ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ์žฌ๊ฒ€์ฆ๋  ์ˆ˜ ์žˆ๋‹ค.

์‹œ๊ฐ„ ๊ธฐ๋ฐ˜ ์žฌ๊ฒ€์ฆ(Time-based Revalidation)

: ์ผ์ • ์‹œ๊ฐ„์ด ์ง€๋‚œ ํ›„ ์ƒˆ๋กœ์šด ์š”์ฒญ์ด ๋ฐœ์ƒํ•œ ํ›„ ๋ฐ์ดํ„ฐ๋ฅผ ์žฌ๊ฒ€์ฆ

fetch('https://...', { next: { revalidate: 60 } })

  • The first time a fetch request withย revalidateย is called, the data will be fetched from the external data source and stored in the Data Cache.
  • 60์ดˆ ์ด๋‚ด์—์„œ๋Š” return the cached data.
  • After the timeframe(60์ดˆ), the next request will still return the cached (์ด์ œ๋Š” ์ตœ์‹ ์ด ์•„๋‹Œ) data.
    • Next.js will trigger a revalidation of the data in the background.
    • Once the data is fetched successfully, Next.js will update the Data Cache with the fresh data.
    • ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์žฌ์œ ํšจํ™”๊ฐ€ ์‹คํŒจํ•˜๋ฉด, ์ด์ „ ๋ฐ์ดํ„ฐ๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์€ ์ฑ„๋กœ ์œ ์ง€๋œ๋‹ค.

์ฃผ๋ฌธํ˜• ์žฌ๊ฒ€์ฆ(On-demand Revalidation:)

:์ด๋ฒคํŠธ(์˜ˆ: ์–‘์‹ ์ œ์ถœ)๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์žฌ๊ฒ€์ฆ

๋ฐ์ดํ„ฐ๋Š” ๊ฒฝ๋กœ(revalidatePath) ๋˜๋Š” ์บ์‹œ ํƒœ๊ทธ(revalidateTag)์— ๋”ฐ๋ผ ํ•„์š”ํ•  ๋•Œ ํ•„์š”์— ๋”ฐ๋ผ ์žฌ์œ ํšจํ™”๋  ์ˆ˜ ์žˆ๋‹ค.

  • ์ฒ˜์Œ์œผ๋กœ fetch ์š”์ฒญ์ด ๋ฐœ์ƒํ•˜๋ฉด, ๋ฐ์ดํ„ฐ๋Š” ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ ์†Œ์Šค์—์„œ ๊ฐ€์ ธ์™€์„œ ๋ฐ์ดํ„ฐ ์บ์‹œ์— ์ €์žฅ๋œ๋‹ค.
  • ํ•„์š”์— ๋”ฐ๋ผ ์žฌ์œ ํšจํ™”๊ฐ€ ํŠธ๋ฆฌ๊ฑฐ(revalidateTag)๋˜๋ฉด, ์ ์ ˆํ•œ ์บ์‹œ ํ•ญ๋ชฉ์ด ์บ์‹œ์—์„œ ์‚ญ์ œ๋ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์‹œ๊ฐ„ ๊ธฐ๋ฐ˜ ์žฌ์œ ํšจํ™”์™€๋Š” ๋‹ค๋ฅด๊ฒŒ ์บ์‹œ์— ์žˆ๋Š” ์ด์ „ ๋ฐ์ดํ„ฐ๋ฅผ fresh ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐ€์ ธ์˜ฌ ๋•Œ๊นŒ์ง€ ์œ ์ง€ํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ๋‹ค์Œ ์š”์ฒญ์—์„œ it will be a cacheย MISSย again, and the data will be fetched from the external data source and stored in the Data Cache.
// Opt out of caching for an individual fetch request
fetch(https://..., { cache: 'no-store' })

cache ์˜ต์…˜์„ no-store๋กœ ์„ค์ •ํ•˜์—ฌ ์บ์‹ฑ์—์„œ ์ œ์™ธํ•  ์ˆ˜ ์žˆ๋‹ค.

export const dynamic = 'force-dynamic'

ํŠน์ • ๊ฒฝ๋กœ ์„ธ๊ทธ๋จผํŠธ์— ๋Œ€ํ•œ ์บ์‹ฑ์„ ์ œ์™ธํ•˜๋ ค๋ฉด Route Segment Config ์˜ต์…˜์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

3. Full Route Cache, Router Cache

Full Route Cache (์ „์ฒด ๋ผ์šฐํŠธ ์บ์‹œ)

Full Route Cache ์ฃผ์š” ๋ชฉ์ ์€ Next.js์—์„œ ๋ผ์šฐํŠธ์˜ ๋ Œ๋”๋ง ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œํ•˜์—ฌ ์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ๋กœ์˜ ๋ฐ˜๋ณต์ ์ธ ๋ Œ๋”๋ง ์š”์ฒญ์„ ์ค„์ด๊ณ , ํŽ˜์ด์ง€ ๋กœ๋“œ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ๊ฒƒ.

์ „์ฒด ๋ผ์šฐํŠธ ์บ์‹œ (Full Route Cache): ์„œ๋ฒ„ ์ธก์—์„œ ํŽ˜์ด์ง€์˜ HTML ๋ Œ๋”๋ง ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œ
๋ผ์šฐํ„ฐ ์บ์‹œ (Route Cache) : ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ๋ฐฉ๋ฌธํ•œ ๊ฒฝ๋กœ ์„ธ๊ทธ๋จผํŠธ๋ฅผ ์บ์‹œํ•˜์—ฌ ์‚ฌ์šฉ์ž์˜ ๊ฒฝ๋กœ ์ด๋™์„ ๋” ๋น ๋ฅด๊ฒŒ ๋งŒ๋“ ๋‹ค.

๋ผ์šฐํ„ฐ ์บ์‹œ์™€ ์ „์ฒด ๊ฒฝ๋กœ ์บ์‹œ์˜ ์ฐจ์ด์ 

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

๊ธฐ๋ณธ์ ์œผ๋กœ next.js์˜ SSG์— ์˜ํ•ด ์ž๋™์œผ๋กœ ์‹คํ–‰ ๋œ๋‹ค.

Router Cache

  • ๋ชฉ์  ๋ผ์šฐํ„ฐ ์บ์‹œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋ผ์šฐํŠธ ๊ฐ„์„ ์ด๋™ํ•˜๋Š” ๋™์•ˆ Next.js๊ฐ€ ๋ฐฉ๋ฌธํ•œ ๋ผ์šฐํŠธ ์„ธ๊ทธ๋จผํŠธ๋ฅผ ์บ์‹œํ•˜๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋™ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ๊ฒฝ๋กœ๋ฅผ ๋ฏธ๋ฆฌ ๊ฐ€์ ธ์˜ด์œผ๋กœ์จ ์‚ฌ์šฉ์ž์˜ ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฒฝํ—˜์„ ํ–ฅ์ƒ์‹œํ‚จ๋‹ค.
  • ๊ธฐ๋Šฅ
    1. ์‚ฌ์šฉ์ž๊ฐ€ ๋ผ์šฐํŠธ ๊ฐ„์„ ์ด๋™ํ•  ๋•Œ ๋ฐฉ๋ฌธํ•œ ๋ผ์šฐํŠธ ์„ธ๊ทธ๋จผํŠธ๋ฅผ ์บ์‹œํ•œ๋‹ค.
    2. ์‚ฌ์šฉ์ž๊ฐ€ ๋ทฐํฌํŠธ์— ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ด๋™ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ๊ฒฝ๋กœ๋ฅผ ๋ฏธ๋ฆฌ ๊ฐ€์ ธ์˜จ๋‹ค.
    3. ๋ฐฉ๋ฌธํ•œ ๊ฒฝ๋กœ๋Š” ์บ์‹œ๋˜์–ด ์ฆ‰์‹œ ์ด์ „/๋‹ค์Œ์œผ๋กœ์˜ ๋„ค๋น„๊ฒŒ์ด์…˜์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋ฉฐ, ๋ฏธ๋ฆฌ ๊ฐ€์ ธ์˜จ ๊ฒฝ๋กœ๋กœ ๋น ๋ฅธ ๋„ค๋น„๊ฒŒ์ด์…˜์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
    4. ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ„์— ์ „์ฒด ํŽ˜์ด์ง€๋ฅผ ๋‹ค์‹œ๋กœ๋“œํ•˜์ง€ ์•Š์œผ๋ฉฐ, React ์ƒํƒœ์™€ ๋ธŒ๋ผ์šฐ์ € ์ƒํƒœ๊ฐ€ ๋ณด์กด๋œ๋‹ค.
    5. ์‚ฌ์šฉ์ž์˜ ๊ฒฝํ—˜์„ ํ–ฅ์ƒ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์ด์ „์— ๋ฐฉ๋ฌธํ•œ ๊ฒฝ๋กœ๋ฅผ ์บ์‹œํ•˜๊ณ , ๋ฏธ๋ž˜์— ์ด๋™ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ๊ฒฝ๋กœ๋ฅผ ๋ฏธ๋ฆฌ ๊ฐ€์ ธ์˜จ๋‹ค.

์ž๋™ ๋ฌดํšจํ™” ๊ธฐ๊ฐ„

๊ฐœ๋ณ„ ์„ธ๊ทธ๋จผํŠธ์˜ ์บ์‹œ๋Š” ํŠน์ • ์‹œ๊ฐ„์ด ์ง€๋‚œ ํ›„ ์ž๋™์œผ๋กœ ๋ฌดํšจํ™”๋œ๋‹ค. ์ด ๊ธฐ๊ฐ„์€ ๊ฒฝ๋กœ๊ฐ€ ์ •์ ์œผ๋กœ ๋˜๋Š” ๋™์ ์œผ๋กœ ๋ Œ๋”๋ง๋˜๋Š”์ง€์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง„๋‹ค.

  • ๋™์ ์œผ๋กœ ๋ Œ๋”๋ง๋œ ๊ฒฝ์šฐ: 30์ดˆ
  • ์ •์ ์œผ๋กœ ๋ Œ๋”๋ง๋œ ๊ฒฝ์šฐ: 5๋ถ„
  • ๊ฐœ๋ณ„ ์„ธ๊ทธ๋จผํŠธ๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ์•ก์„ธ์Šค๋˜๊ฑฐ๋‚˜ ์ƒ์„ฑ๋œ ์‹œ๊ฐ„๋ถ€ํ„ฐ ์˜ํ–ฅ์„ ๋ฐ›๋Š”๋‹ค.

๋ผ์šฐํ„ฐ ์บ์‹œ ๋ฌดํšจํ™” ์˜ˆ์ œ

    import { useRouter } from 'next/router';
    import { cookies } from 'cookies-library'; // ์ฟ ํ‚ค ๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
    
    // useRouter ํ›…์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ผ์šฐํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
    const router = useRouter();
    
    // ์„œ๋ฒ„ ์•ก์…˜์—์„œ revalidatePath ๋˜๋Š” revalidateTag๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์žฌ์œ ํšจํ™”ํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.
    // ๊ฒฝ๋กœ๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์žฌ์œ ํšจํ™”ํ•  ๊ฒฝ์šฐ
    const revalidatePath = '/api/data'; // ์žฌ์œ ํšจํ™”ํ•  ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
    router.revalidate(revalidatePath);
    
    // ์บ์‹œ ํƒœ๊ทธ๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์žฌ์œ ํšจํ™”ํ•  ๊ฒฝ์šฐ
    const revalidateTag = 'data-tag'; // ์žฌ์œ ํšจํ™”ํ•  ์บ์‹œ ํƒœ๊ทธ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
    router.revalidate({ tag: revalidateTag });
    
    // cookies.set ๋˜๋Š” cookies.delete๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฟ ํ‚ค๋ฅผ ํ†ตํ•ด ๋ผ์šฐํ„ฐ ์บ์‹œ๋ฅผ ๋ฌดํšจํ™”ํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.
    // ์ฟ ํ‚ค๋ฅผ ์„ค์ •ํ•˜์—ฌ ๋ผ์šฐํ„ฐ ์บ์‹œ๋ฅผ ๋ฌดํšจํ™”ํ•  ๊ฒฝ์šฐ
    const cookieName = 'auth'; // ๋ฌดํšจํ™”ํ•  ์ฟ ํ‚ค์˜ ์ด๋ฆ„์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
    const cookieValue = 'expired'; // ์ฟ ํ‚ค์˜ ๊ฐ’์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
    cookies.set(cookieName, cookieValue);
    
    // ์ฟ ํ‚ค๋ฅผ ์‚ญ์ œํ•˜์—ฌ ๋ผ์šฐํ„ฐ ์บ์‹œ๋ฅผ ๋ฌดํšจํ™”ํ•  ๊ฒฝ์šฐ
    cookies.delete(cookieName);
    
    // router.refresh๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ผ์šฐํ„ฐ ์บ์‹œ๋ฅผ ๋ฌดํšจํ™”ํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.
    router.refresh();

router.refresh, revalidatePath ๋˜๋Š” revalidateTag๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฌดํšจํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์บ์‹œ๊ฐ€ ์ง€์›Œ์ง€๊ณ  ์„œ๋ฒ„์— ์ƒˆ๋กœ์šด ์š”์ฒญ์ด ๋ณด๋‚ด์ ธ ์ตœ์‹  ๋ฐ์ดํ„ฐ๊ฐ€ ํ‘œ์‹œ๋œ๋‹ค.

๋ผ์šฐํ„ฐ ์บ์‹œ ์ ์šฉ ์˜ˆ์ œ

    const router = useRouter();
    ...
    router.prefetch('/about'); 
    
    <Link href="/example" **prefetch={true}**>
      <a>Example Page</a>
    </Link>

router.prefetch('/about')๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด Next.js๋Š” ์‚ฌ์šฉ์ž๊ฐ€ '/about' ๊ฒฝ๋กœ๋กœ ์ด๋™ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ณ  ํ•ด๋‹น ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฏธ๋ฆฌ ๊ฐ€์ ธ์˜จ๋‹ค. ์ด๊ฒƒ์€ ํŽ˜์ด์ง€๋ฅผ ๋ฐฉ๋ฌธํ•˜๊ธฐ ์ „์— ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์ „๋กœ๋“œํ•˜์—ฌ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋‹ค.

์‹ค์ œ๋กœ ์‚ฌ์šฉ์ž๊ฐ€ '/about' ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜์ง€ ์•Š์•„๋„ ์ด ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ์‚ฌ์ „์— ๊ฐ€์ ธ์™€์ง€๋ฏ€๋กœ, ์‚ฌ์šฉ์ž๊ฐ€ ํ•ด๋‹น ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•  ๋•Œ ๋” ๋น ๋ฅธ ๋กœ๋”ฉ ์†๋„์™€ ๋ถ€๋“œ๋Ÿฌ์šด ํŽ˜์ด์ง€ ์ „ํ™˜์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค.

profile
๋šœ์ž‡๋šœ์ž‡ FE๊ฐœ๋ฐœ์ž

0๊ฐœ์˜ ๋Œ“๊ธ€