๐ก ์บ์ฑ ๋์ : ๋ ๋๋ง ์์
, ๋ฐ์ดํฐ ์์ฒญ
๐ก ๋ชฉ์ : ์ ํ๋ฆฌ์ผ์ด์
์ฑ๋ฅ์ ํฅ์, ๋น์ฉ ์ ๊ฐ
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์ ์บ์๋ ์ฑ๋ฅํฅ์๊ณผ ๋น์ฉ ์ ๊ฐ์ ๊ฐ๋ฅํ๊ฒ ํ๋ค. ์ด๊ฒ์ ์๋ฏธ๋ ๊ฒฝ๋ก๋ย ์ ์ ์ผ๋ก ๋ ๋๋ง๋๊ณ ย ๋ฐ์ดํฐ ์์ฒญ์ย ์บ์ ๋๋ค๋ ๊ฒ์ด๋ค.
๋งค์ปค๋์ฆ | What | Where | Purpose | Duration |
---|---|---|---|---|
https://nextjs.org/docs/app/building-your-application/caching#request-memoization | ํจ์์ ๋ฐํ ๊ฐ | server | React ๊ตฌ์ฑ ์์ ํธ๋ฆฌ์์ ๋ฐ์ดํฐ ์ฌ์ฌ์ฉ | ์์ฒญ๋ณ ์๋ช ์ฃผ๊ธฐ |
https://nextjs.org/docs/app/building-your-application/caching#data-cache | ๋ฐ์ดํฐ | server | ์ฌ์ฉ์ ์์ฒญ ๋ฐ ๋ฐฐํฌ ์ ๋ฐ์ ๊ฑธ์ณ ๋ฐ์ดํฐ ์ ์ฅ | ์ง์์ (์ฌ๊ฒ์ฆ ๊ฐ๋ฅ) |
https://nextjs.org/docs/app/building-your-application/caching#full-route-cache | HTML ๋ฐ RSC ํ์ด๋ก๋ | server | ๋ ๋๋ง ๋น์ฉ ์ ๊ฐ ๋ฐ ์ฑ๋ฅ ํฅ์ | ์ง์์ (์ฌ๊ฒ์ฆ ๊ฐ๋ฅ) |
https://nextjs.org/docs/app/building-your-application/caching#router-cache | RSC ํ์ด๋ก๋ | client | ํ์ ์ ์๋ฒ ์์ฒญ ์ค์ด๊ธฐ | ์ฌ์ฉ์ ์ธ์ ๋๋ ์๊ฐ ๊ธฐ๋ฐ |
React๋ย fetch
API๋ฅผ(https://nextjs.org/docs/app/building-your-application/caching#fetch)ย ํ์ฅํ์ฌ ๋์ผํ URL๊ณผ ์ต์
์ ๊ฐ์ง ์์ฒญ์ย ์๋์ผ๋กย ๋ฉ๋ชจํ๋ค.ย ์ด๋ React ์ปดํฌ๋ํธ ํธ๋ฆฌ์ ์ฌ๋ฌ ์์น์์ ๋์ผํ ๋ฐ์ดํฐ์ ๋ํ ๊ฐ์ ธ์ค๊ธฐ ํจ์๋ฅผ ํ ๋ฒ๋ง ์คํํ๋ฉด์ ํธ์ถํ ์ ์์์ ์๋ฏธํ๋ค.
React ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง๋๋ ๋์
์๋ง ์บ์๋ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ฑ๋ฅ์ ํฅ์์ํค๊ณ , ์ค๋ณต๋ ์์ฒญ์ ๋ฐฉ์งํ๊ธฐ ์ํด ์ฌ์ฉ๋ฉ๋๋ค.
๐ก ์ฃผ์ ๋ชฉ์
์ผ๋ฐ์ ์ผ๋ก ํ์ด์ง๋ฅผ ๋ ๋๋งํ ๋ ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ผ ํ๋๋ฐ, ์ด๋ฅผ ์ฌ๋ฌ ์ปดํฌ๋ํธ์์ ์ค๋ณตํด์ ์์ฒญํ๋ ๊ฒ์ ๋นํจ์จ์ ์ผ ์ ์๋ค. ๋ฐ๋ผ์ ํ ๋ฒ ์์ฒญ๋ ๋ฐ์ดํฐ๋ฅผ ์บ์ํ์ฌ ์ฌ๋ฌ ์ปดํฌ๋ํธ์์ ์ฌ์ฌ์ฉํ ์ ์๊ฒํ๋ค.
๐ก Thefetch
function is automatically memoized and the result is cached.
(์ฐธ๊ณ ) Request Memoization๋ next.js๊ฐ ์๋ react์ ๊ธฐ๋ฅ์ด๋ค.
MISS
SET
HIT
( ๋ฐ์ดํฐ๋ ํจ์๋ฅผ ์คํํ์ง ์๊ณ ๋ฉ๋ชจ๋ฆฌ์์ ๋ฐํ๋๋ค.๐ก route : ํน์ URL์ ํด๋นํ๋ ํ์ด์ง ๋๋ ๊ฒฝ๋ก
ex) /about
๐ก redering pass : ํ์ด์ง๋ฅผ ๋ ๋๋งํ๋ ๊ณผ์ . ๋ผ์ฐํธ ๋งค์นญ, ๋ ๋๋ง, ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๋ฑ ๊ณผ์ ์ด ํฌํจ๋๋ค.
Next.js์๋ ๋ด์ฅ๋ ๋ฐ์ดํฐ ์บ์๊ฐ ์๋ค. ์ด ์บ์๋ ์๋ฒ ์์ฒญ ๋ฐ ๋ฐฐํฌ๋ฅผ ํตํด ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ์ ๊ฒฐ๊ณผ๋ฅผ ์ ์งํ๋ค.
Next.js extends the nativeย
fetch
ย API to allow each request on the server to set its own persistent caching semantics.
์ฒ์ ๋ ๋๋ง ์ค์ fetch ์์ฒญ์ด ํธ์ถ๋๋ฉด, Next.js๋ ์บ์๋ ์๋ต์ ํ์ธํ๊ธฐ ์ํด ๋ฐ์ดํฐ ์บ์๋ฅผ ํ์ธํ๋ค.
์บ์๋ ์๋ต์ด ๋ฐ๊ฒฌ๋๋ฉด ์ฆ์ ๋ฐํ๋๊ณ ๋ฉ๋ชจ์ด์ ์ด์ ๋๋ค. ์บ์๋ ์๋ต์ด ๋ฐ๊ฒฌ๋์ง ์์ผ๋ฉด ๋ฐ์ดํฐ ์์ค๋ก ์์ฒญ์ด ์ด๋ฃจ์ด์ง๊ณ , ๊ฒฐ๊ณผ๊ฐ ๋ฐ์ดํฐ ์บ์์ ์ ์ฅ๋๊ณ ๋ฉ๋ชจ์ด์ ์ด์ ๋๋ค.
์บ์๋์ง ์์ ๋ฐ์ดํฐ์ ๊ฒฝ์ฐ(์: { cache: 'no-store' }), ํญ์ ๋ฐ์ดํฐ ์์ค์์ ๊ฒฐ๊ณผ๊ฐ ๊ฐ์ ธ์์ง๊ณ ๋ฉ๋ชจ์ด์ ์ด์ ๋๋ค. ๋ฐ์ดํฐ๊ฐ ์บ์๋์๋ ์บ์๋์ง ์์๋ , ์์ฒญ์ ํญ์ ๋ฉ๋ชจ์ด์ ์ด์ ๋์ด React ๋ ๋๋ง ํจ์ค ์ค์ ๋์ผํ ๋ฐ์ดํฐ์ ๋ํ ์ค๋ณต ์์ฒญ์ด ๋ฐ์ํ์ง ์๋๋ก ํ๋ค.
Differences between the Data Cache
and Request Memoization
์ง์์ฑ (Persistence):
๋คํธ์ํฌ ๊ต์ฐจ์ (Network Boundary):
๐ก ๋คํธ์ํฌ ๊ต์ฐจ์ : ๋ฐ์ดํฐ๊ฐ ๋คํธ์ํฌ๋ฅผ ํตํด ์ด๋ํ๋ ๋์ ๋ฐ์ดํฐ๊ฐ ๊ฒฝ์ ํ๋ ์ง์
๋ฐ์ดํฐ ์บ์๋ ์ฌ๊ฒ์ฆํ๊ฑฐ๋ ์ ํ ํด์ ํ์ง ์๋ ํ ๋ค์ด์ค๋ ์์ฒญ ๋ฐ ๋ฐฐํฌ ์ ๋ฐ์ ๊ฑธ์ณ ์ง์๋๋ค.
์บ์๋ ๋ฐ์ดํฐ๋ ๋ค์ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก ์ฌ๊ฒ์ฆ๋ ์ ์๋ค.
: ์ผ์ ์๊ฐ์ด ์ง๋ ํ ์๋ก์ด ์์ฒญ์ด ๋ฐ์ํ ํ ๋ฐ์ดํฐ๋ฅผ ์ฌ๊ฒ์ฆ
fetch('https://...', { next: { revalidate: 60 } })
revalidate
ย is called, the data will be fetched from the external data source and stored in the Data Cache.:์ด๋ฒคํธ(์: ์์ ์ ์ถ)๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฌ๊ฒ์ฆ
๋ฐ์ดํฐ๋ ๊ฒฝ๋ก(revalidatePath) ๋๋ ์บ์ ํ๊ทธ(revalidateTag)์ ๋ฐ๋ผ ํ์ํ ๋ ํ์์ ๋ฐ๋ผ ์ฌ์ ํจํ๋ ์ ์๋ค.
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 ์ต์ ์ ์ฌ์ฉํ ์๋ ์๋ค.
Full Route Cache ์ฃผ์ ๋ชฉ์ ์ Next.js์์ ๋ผ์ฐํธ์ ๋ ๋๋ง ๊ฒฐ๊ณผ๋ฅผ ์บ์ํ์ฌ ์๋ฒ์์ ํด๋ผ์ด์ธํธ๋ก์ ๋ฐ๋ณต์ ์ธ ๋ ๋๋ง ์์ฒญ์ ์ค์ด๊ณ , ํ์ด์ง ๋ก๋ ์ฑ๋ฅ์ ํฅ์์ํค๋ ๊ฒ.
์ ์ฒด ๋ผ์ฐํธ ์บ์ (Full Route Cache): ์๋ฒ ์ธก์์ ํ์ด์ง์ HTML ๋ ๋๋ง ๊ฒฐ๊ณผ๋ฅผ ์บ์
๋ผ์ฐํฐ ์บ์ (Route Cache) : ํด๋ผ์ด์ธํธ ์ธก์์ ์ฌ์ฉ์๊ฐ ๋ฐฉ๋ฌธํ ๊ฒฝ๋ก ์ธ๊ทธ๋จผํธ๋ฅผ ์บ์ํ์ฌ ์ฌ์ฉ์์ ๊ฒฝ๋ก ์ด๋์ ๋ ๋น ๋ฅด๊ฒ ๋ง๋ ๋ค.
๋ผ์ฐํฐ ์บ์์ ์ ์ฒด ๊ฒฝ๋ก ์บ์์ ์ฐจ์ด์
๊ธฐ๋ณธ์ ์ผ๋ก next.js์ SSG์ ์ํด ์๋์ผ๋ก ์คํ ๋๋ค.
๊ฐ๋ณ ์ธ๊ทธ๋จผํธ์ ์บ์๋ ํน์ ์๊ฐ์ด ์ง๋ ํ ์๋์ผ๋ก ๋ฌดํจํ๋๋ค. ์ด ๊ธฐ๊ฐ์ ๊ฒฝ๋ก๊ฐ ์ ์ ์ผ๋ก ๋๋ ๋์ ์ผ๋ก ๋ ๋๋ง๋๋์ง์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ค.
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' ํ์ด์ง๋ก ์ด๋ํ์ง ์์๋ ์ด ๊ฒฝ๋ก์ ๋ํ ๋ฐ์ดํฐ๊ฐ ์ฌ์ ์ ๊ฐ์ ธ์์ง๋ฏ๋ก, ์ฌ์ฉ์๊ฐ ํด๋น ํ์ด์ง๋ก ์ด๋ํ ๋ ๋ ๋น ๋ฅธ ๋ก๋ฉ ์๋์ ๋ถ๋๋ฌ์ด ํ์ด์ง ์ ํ์ ์ ๊ณตํ ์ ์๋ค.
Router.refresh()๋ก ์ด๊ธฐํ ํด์ค์ ์๋ค๋์ .. ๋๋ถ์ ์ฑ๊ณต์ ์ผ๋ก ์บ์ ์ฌ์ดํด์ด ์ ์์ ์ผ๋ก ์ ๋์๊ฐ๋ค์! ๊ฐ์ฌ