서버 컴포넌트에서 fetch 하고 캐시를 제어한다.
데이터 패칭과 캐싱
App Router에서 데이터 패칭은 놀랄 만큼 단순합니다. 서버 컴포넌트를 async 로 만들고 그냥 await fetch(...) 하면 됩니다. 대신 Next.js가 fetch 를 확장해 강력한 캐싱을 더했기 때문에, 그 동작을 이해하는 게 핵심입니다.
학습 목표
- 서버 컴포넌트에서
async/await로 데이터를 읽는다. fetch의 캐시 옵션(force-cache,no-store,revalidate)을 구분한다.- 병렬 패칭과 순차 패칭의 차이와 폭포(waterfall)를 피하는 법을 안다.
- 같은 요청이 자동으로 합쳐지는 request memoization을 이해한다.
서버 컴포넌트에서 패칭
별도 라이브러리 없이 컴포넌트 안에서 바로 데이터를 가져옵니다.
// app/products/page.tsx
export default async function Products() {
const res = await fetch('https://api.example.com/products');
const products = await res.json();
return (
<ul>
{products.map((p: { id: number; name: string }) => (
<li key={p.id}>{p.name}</li>
))}
</ul>
);
}
서버에서 실행되므로 API 키를 헤더에 붙여도 브라우저에 노출되지 않습니다.
fetch 캐시 옵션
Next.js의 fetch 는 결과를 캐시할 수 있습니다. cache 와 next.revalidate 옵션으로 제어합니다.
// 1) 영구 캐시 (정적): 빌드 결과를 재사용
await fetch(url, { cache: 'force-cache' });
// 2) 매번 새로: 캐시하지 않음 (항상 최신)
await fetch(url, { cache: 'no-store' });
// 3) 시간 기반 재검증: 60초마다 새로 가져옴 (ISR)
await fetch(url, { next: { revalidate: 60 } });
| 옵션 | 동작 | 쓰임 |
|---|---|---|
force-cache | 한 번 받고 계속 재사용 | 잘 안 바뀌는 데이터 |
no-store | 매 요청마다 새로 | 실시간·개인화 데이터 |
next: { revalidate: N } | N초마다 갱신 | 적당히 자주 바뀌는 데이터 |
💡 TIP — 라우트 전체의 동작을 한 번에 바꾸려면 페이지 파일에
export const dynamic = 'force-dynamic'또는export const revalidate = 60을 둘 수도 있습니다. (다음 레슨에서 자세히)
병렬 vs 순차 패칭
여러 데이터를 가져올 때, 무심코 await 를 줄줄이 쓰면 폭포(waterfall) 가 생깁니다. 앞 요청이 끝나야 다음이 시작되어 느려집니다.
// ❌ 순차: user 끝나야 posts 시작 (느림)
const user = await getUser();
const posts = await getPosts();
서로 의존하지 않는 요청은 Promise.all 로 동시에 보냅니다.
// ✅ 병렬: 둘을 동시에 요청
const [user, posts] = await Promise.all([getUser(), getPosts()]);
⚠️ 주의 — 다음 요청이 앞 요청의 결과를 필요로 할 때만 순차로 두세요. 그렇지 않다면 거의 항상 병렬이 빠릅니다.
Request Memoization
같은 렌더링 패스 안에서 완전히 동일한 fetch 요청(같은 URL, 같은 옵션)을 여러 번 호출하면, Next.js가 자동으로 한 번만 실제 요청하고 결과를 공유합니다. 그래서 데이터를 props로 줄줄이 내려보내지 않고, 필요한 컴포넌트에서 각자 fetch 해도 됩니다.
// 같은 요청이 두 번 호출되어도 실제 네트워크 요청은 1회
async function getUser() {
const res = await fetch('https://api.example.com/me'); // 자동 합쳐짐
return res.json();
}
// Layout 에서 한 번, Page 에서 한 번 호출해도 OK
이 덕분에 "데이터를 위에서 한 번 받아 아래로 전달" 하는 prop drilling을 줄일 수 있습니다.
요약
- 서버 컴포넌트를
async로 만들고await fetch로 데이터를 읽는다. force-cache/no-store/revalidate로 캐시 동작을 고른다.- 의존성이 없는 요청은
Promise.all로 병렬화해 폭포를 피한다. - 동일한
fetch는 자동으로 합쳐진다(request memoization).
연습문제
- 공개 API를 골라
no-store와revalidate: 30으로 각각 패칭하고, 새로고침 시 데이터가 어떻게 다른지 관찰하세요. - 서로 독립적인 두 API 호출을
Promise.all로 병렬화해 보세요. - 같은
fetch를 두 컴포넌트에서 호출해도 네트워크 요청이 한 번만 일어나는지 개발자 도구로 확인하세요. - 어떤 데이터에
force-cache가 적합하고, 어떤 데이터에no-store가 적합한지 예를 두 개씩 적어 보세요.
힌트 — 순차
await두 줄을Promise.all([a(), b()])로 바꾸면 됩니다. 캐시 동작이 헷갈리면 네트워크 탭과 응답 시간을 비교해 보세요.
💡 연습문제 풀이
불러오는 중…
댓글 0
“Next.js” 강좌에 대한 댓글입니다.