본문 바로가기
Frontend2026년 5월 23일3분 읽기

React Server Components — cache() API 1년 실전, 6가지 패턴

YS
김영삼
조회 89
React Server Components — cache() API 1년 실전, 6가지 패턴

핵심 요약

React cache()는 "요청 단위 memoization"이지 데이터 캐시가 아니다. 1년 운영으로 정착한 6가지 패턴 — fetch 중복 제거, 권한 체크 단일화, ORM 호출 최소화, 직렬화 우회, 인자 정규화, layout-page 분리. 잘못 쓰면 메모리 누수와 동등성 미스로 캐시가 항상 미스.

1. cache() ≠ 데이터 캐시

cache()는 같은 요청 안에서만 동일 인자 호출을 memoize. 요청이 끝나면 사라진다. CDN 캐시, 디스크 캐시 아님. 데이터 캐시는 unstable_cache 또는 'use cache' 디렉티브.

2. 패턴 1 — 권한 체크 단일화

import { cache } from 'react'
import { cookies } from 'next/headers'

export const getUser = cache(async () => {
  const token = (await cookies()).get('session')?.value
  if (!token) return null
  return verifyJWT(token)
})

layout, page, 5개 component에서 getUser() 호출해도 JWT 검증은 1번. DB hit 5→1.

3. 패턴 2 — 동등성 키 정규화

인자는 참조 동등성(===). 객체 매번 새로 만들면 캐시 매번 미스. 객체 인자는 JSON.stringify로 키 변환 또는 primitive로 분해.

// ❌ 매번 새 객체 — 캐시 미스
getPost(cache({id, locale}))
// ✅ primitive
const _getPost = cache(async (id: number, locale: string) => {...})

4. 패턴 3 — 직렬화 함정

Server Component 사이로 props 넘기면 직렬화. Date, Map, Set은 통과 못하니 ISO 문자열·배열로 변환. cache()로 감싼 함수가 Map을 반환하면 client component에서 받을 때 에러.

5. 패턴 4 — layout-page 분리 호출

layout과 page에서 같은 getUser() 호출 시 layout이 먼저 await되면 page가 캐시 hit. Promise.all로 병렬 awaiting하면 두 번 다 hit. preload 패턴이 강력.

6. 함정 정리

  • 'use server' 액션 안에서 cache() — 액션 호출마다 새 요청이라 무의미
  • cache(fn)을 매번 새로 만들기 — 인스턴스가 다르면 캐시 따로
  • 에러 캐시 — throw도 memoize. 에러 응답을 캐싱하기 싫으면 try-catch로 일반 반환
  • Client Component에서 cache() 쓰기 — no-op, 경고도 안 나옴

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록