๐Ÿง  Next.js์—์„œ ๋ฐ˜๋“œ์‹œ ์•Œ์•„์•ผ ํ•  4๊ฐ€์ง€ ์บ์‹ฑ ์ „๋žต

LinkDropperยท2025๋…„ 5์›” 23์ผ
12

Others

๋ชฉ๋ก ๋ณด๊ธฐ
1/4
post-thumbnail

๐Ÿ— ์บ์‹œ ์ „๋žต์„ ์•Œ์•„์•ผ ํ•˜๋Š” ์ด์œ 

Next.js๋Š” app router ๊ธฐ๋ฐ˜ ํ”„๋กœ์ ํŠธ์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ fetch์™€ page rendering์„ SSR(Server Side Rendering) ๋˜๋Š” SSG(Static Site Generation) ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์บ์‹œ ์ „๋žต์„ ์–ด๋–ป๊ฒŒ ์“ฐ๋А๋ƒ์— ๋”ฐ๋ผ ํŽ˜์ด์ง€์˜ ์„ฑ๋Šฅ, ์‚ฌ์šฉ์ž ๊ฒฝํ—˜, SEO๊ฐ€ ์ขŒ์šฐ๋ฉ๋‹ˆ๋‹ค.


๐Ÿงฉ ์บ์‹ฑ ์ „๋žต โ‘  Request Cache (์š”์ฒญ ์บ์‹œ)

๋™์ผํ•œ fetch ์š”์ฒญ์€ ํ•œ ๋ฒˆ๋งŒ ์ฒ˜๋ฆฌํ•˜๊ณ , ์ดํ›„์—๋Š” ๊ฒฐ๊ณผ๋ฅผ ์žฌ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

โœ… ํŠน์ง•

  • ๊ฐ™์€ fetch ์š”์ฒญ์ด ์—ฌ๋Ÿฌ ๋ฒˆ ์žˆ์–ด๋„, ํ•œ ๋ฒˆ๋งŒ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ๋ฐœ์ƒ
  • ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ ๊ธฐ๋ฐ˜ (์„œ๋ฒ„์—์„œ๋งŒ ์ž‘๋™)
  • ์„œ๋ฒ„๋ฆฌ์Šค ํ™˜๊ฒฝ์—์„œ๋Š” ์ธ์Šคํ„ด์Šค ๊ฐ„ ์บ์‹œ ๊ณต์œ  ์•ˆ ๋จ

โœ… ์˜ˆ์‹œ ์ฝ”๋“œ

const A = async () => await fetch('/api/workspace');
const B = async () => await fetch('/api/workspace'); 
// ๊ฐ™์€ ์š”์ฒญ, ํ•œ ๋ฒˆ๋งŒ ์š”์ฒญ๋จ

โ—๏ธ์ฃผ์˜์‚ฌํ•ญ

  • URL, ์ฟผ๋ฆฌ, ํ—ค๋” ๋“ฑ์ด ๋ชจ๋‘ ์ผ์น˜ํ•ด์•ผ ์บ์‹ฑ๋ฉ๋‹ˆ๋‹ค.
  • ๊ณผ๋„ํ•œ ์บ์‹œ๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋ฌธ์ œ๋ฅผ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ์Œ

๐Ÿ”ง ์บ์‹œ ๋ฌดํšจํ™” ๋ฐฉ๋ฒ•

await fetch('/api/data', {
  next: { cache: 'no-store' }
});

๐Ÿงฑ ์บ์‹ฑ ์ „๋žต โ‘ก Build-time Cache (๋นŒ๋“œ ํƒ€์ž„ ์บ์‹œ)

next build ์‹œ์ ์— fetch๋ฅผ ์‹คํ–‰ํ•˜๊ณ , ์ •์ ์œผ๋กœ ์บ์‹ฑํ•ฉ๋‹ˆ๋‹ค.

โœ… ํŠน์ง•

  • ๋นŒ๋“œ ์‹œ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ณ ์ •
  • ์‹ค์ œ ๋ฐฐํฌ ํ™˜๊ฒฝ์—์„œ๋Š” auto ์บ์‹œ ์ •์ฑ…์ด์ง€๋งŒ, ์ •์  fetch๋Š” force-cache์ฒ˜๋Ÿผ ๋™์ž‘

๐Ÿ˜จ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค

const TodoListPage = async () => {
  const todos = await getTodoList();
  return (
    <ul>
      {todos.map((todo, i) => <li key={i}>{todo}</li>)}
    </ul>
  );
}

const CreateTodoPage = () => {
  const onSaveTodo = async () => {
    await saveTodo();
    router.push('/todo-list');
  }

  return <button onClick={onSaveTodo}>์ƒ์„ฑ</button>;
}

๐Ÿ›  ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

  1. no-store ์‚ฌ์šฉ (ํ•ญ์ƒ ์ตœ์‹  ๋ฐ์ดํ„ฐ)
  2. revalidateTag๋กœ ํŠน์ • ์บ์‹œ ๋ฌดํšจํ™”
await fetch('/api/todos', {
  next: { tags: ['todos'] }
});

revalidateTag('todos');

๐Ÿ“ฆ ์บ์‹ฑ ์ „๋žต โ‘ข Page Cache (ํŽ˜์ด์ง€ ์บ์‹œ)

์œ ์ €๊ฐ€ ๋ฐฉ๋ฌธํ•œ ํŽ˜์ด์ง€๋ฅผ ์บ์‹ฑํ•˜์—ฌ ๋‹ค์Œ ์š”์ฒญ ์‹œ ๋น ๋ฅด๊ฒŒ ์‘๋‹ตํ•ฉ๋‹ˆ๋‹ค.

โœ… ํŠน์ง•

  • ์š”์ฒญ ์‹œ SSR ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅ
  • ์ดํ›„ ๊ฐ™์€ ์š”์ฒญ์ด ์˜ค๋ฉด ์บ์‹œ๋กœ ์‘๋‹ต
  • ISR ๊ธฐ๋ฐ˜์œผ๋กœ ์ž‘๋™ํ•จ
๋น„๊ต ํ•ญ๋ชฉBuild-time CachePage Cache
์ƒ์„ฑ ์‹œ์ ๋นŒ๋“œ ์‹œ์š”์ฒญ ์‹œ
๊ฐฑ์‹  ์‹œ์ ISR ๋˜๋Š” ์žฌ๋ฐฐํฌ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋ฌดํšจํ™” ๊ฐ€๋Šฅ
์‚ฌ์šฉ ์‚ฌ๋ก€๋งˆ์ผ€ํŒ… ํŽ˜์ด์ง€๋กœ๊ทธ์ธ ํ›„ ๋Œ€์‹œ๋ณด๋“œ

๐Ÿš€ ์บ์‹ฑ ์ „๋žต โ‘ฃ Prefetch Cache (์‚ฌ์ „ ๋กœ๋”ฉ ์บ์‹œ)

์œ ์ €๊ฐ€ ์•„์ง ํด๋ฆญํ•˜์ง€ ์•Š์€ ๋งํฌ์— ๋Œ€ํ•ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๋ฏธ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

โœ… ์ž‘๋™ ์›๋ฆฌ

  • <Link>๋Š” ์ •์  ๊ฒฝ๋กœ์— ๋Œ€ํ•ด ์ž๋™ prefetch
  • Intersection Observer๋กœ ๋ทฐํฌํŠธ ๋‚ด์—์„œ๋งŒ ์ž‘๋™
  • ๋ธŒ๋ผ์šฐ์ € ์บ์‹œ ํ™œ์šฉ
<Link href="/about">About</Link>
<Link href="/about" prefetch={false}>About</Link>

๐Ÿ’ก ์„ฑ๋Šฅ์„ ์œ„ํ•ด ์บ์‹œ ์ „๋žต์„ ๋” ์ž˜ ์“ฐ๋Š” ํŒ

1. fetch๋Š” props ์ „๋‹ฌ ๋Œ€์‹ , ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋‹ค์‹œ ํ˜ธ์ถœ

const Parent = () => <Child />
const Child = async () => {
  const data = await fetchData();
}

2. Client Component๋Š” ๊ผญ ํ•„์š”ํ•œ ๊ฒฝ์šฐ๋งŒ ์‚ฌ์šฉ

const Page = () => <ModalButton />

3. ์„œ๋ฒ„์—์„œ fetch ํ›„ ํด๋ผ์ด์–ธํŠธ์— ์ „๋‹ฌ

const Server = async () => {
  const data = await fetchData();
  return <Client data={data} />
}

๐Ÿ“š ์ฐธ๊ณ  ์ž๋ฃŒ


๐Ÿ—‚ Words

๋‹จ์–ด๋œป๋ฐœ์Œ
Cache์ €์žฅ๋œ ๋ฐ์ดํ„ฐ[kรฆสƒ]
Prefetch์‚ฌ์ „ ๋กœ๋”ฉ[priหหˆfetสƒ]
Revalidate์žฌ๊ฒ€์ฆํ•˜๋‹ค[หŒriหหˆvรฆlษชdeษชt]
Tagํƒœ๊ทธ (๋ถ„๋ฅ˜ ๋‹จ์œ„)[tรฆษก]
Observer๊ด€์ฐฐ์ž[ษ™bหˆzษœหrvษ™r]

๐Ÿ“ข ํ•จ๊ป˜ ๋ณด๋ฉด ์ข‹์€ ์†Œ์‹

๐Ÿงช ๋งํฌ ๋“œ๋ผํผ, ์ง€๊ธˆ ๋ฒ ํƒ€ ํ…Œ์ŠคํŠธ ์ค‘์ž…๋‹ˆ๋‹ค

๋งํฌ ๋“œ๋ผํผ๋Š” ๋งํฌ๋ฅผ ์ €์žฅํ•˜๊ณ ,
์ •๋ฆฌํ•˜๊ณ ,
๋‹ค์‹œ ๊บผ๋‚ด๋ณด๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค.

  • ๐Ÿ“Ž ํด๋”๋ณ„ ๋งํฌ ์ •๋ฆฌ
  • โœจ OG ์ด๋ฏธ์ง€ ์ž๋™ ์ถ”์ถœ
  • ๐Ÿง  ๊ณต์œ  URL ์ƒ์„ฑ ๋ฐ ๊ฒŒ์‹œ ๊ธฐ๋Šฅ
  • โšก ํฌ๋กฌ ์ต์Šคํ…์…˜ ์›ํด๋ฆญ ์ €์žฅ

๐Ÿ‘‰ ๋งํฌ ๋“œ๋ผํผ ๋ฒ ํƒ€ ์ฒดํ—˜ํ•˜๋Ÿฌ ๊ฐ€๊ธฐ
๐Ÿ‘‰ ํฌ๋กฌ ์›น์Šคํ† ์–ด์—์„œ ์„ค์น˜ํ•˜๊ธฐ


๐Ÿ’ฌ ์นด์นด์˜คํ†ก ์ฑ„๋„ ์ถ”๊ฐ€ํ•˜๊ณ  ์†Œ์‹ ๋ฐ›๊ธฐ

  • ์„œ๋น„์Šค ์—…๋ฐ์ดํŠธ
  • ๊ธฐ๋Šฅ ๊ฟ€ํŒ
    ์นด์นด์˜คํ†ก ์ฑ„๋„์„ ํ†ตํ•ด ๋น ๋ฅด๊ฒŒ ๋ฐ›์•„๋ณด์„ธ์š”!

๐Ÿ‘‰ ์นด์นด์˜คํ†ก ์ฑ„๋„ ์ถ”๊ฐ€ํ•˜๊ธฐ

profile
โ€œ๊ธฐ๋กํ•˜๋Š” ์Šต๊ด€์„ ๋„๊ตฌ๋กœ ๋งŒ๋“ค๋‹ค โ€” ๋‘ ๊ฐœ๋ฐœ์ž์˜ ๋งํฌ ๋“œ๋ผํผ ๊ตฌ์ถ•๊ธฐโ€

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