Next.js 15, TypeScript, 그리고 두 가지 통합 예제를 사용한 정교한 LocalStorage 캐시 구현으로 클라이언트 사이드 캐싱 패턴을 종합적으로 보여주는 프로젝트입니다.
이 프로젝트는 클라이언트 사이드 데이터 캐싱을 구현하는 두 가지 다른 접근 방식을 보여줍니다:
- 바닐라 React 구현 (
/) - 수동 상태 관리와 함께 LocalStorageCache 직접 사용 - React Query 통합 (
/react-query) - React Query의 강력한 캐싱과 영구 LocalStorage 결합
- 네임스페이스 격리: 별도 네임스페이스를 가진 다중 캐시 인스턴스
- LRU 제거: 가장 최근에 사용되지 않은 항목의 자동 정리
- 설정 가능한 리셋 스케줄: 일일, 시간별, 분 단위, 또는 커스텀 간격
- 크기 및 항목 제한: 네임스페이스별 설정 가능한 메모리 관리
- SSR 호환: Next.js 환경에서 localStorage의 안전한 처리
- TypeScript 지원: 전체적인 완전한 타입 안전성
- 실시간 캐시 모니터링: 실시간 통계 및 리셋 타이머
- 인터랙티브 데이터 페칭: JSONPlaceholder API의 사용자, 게시물, 할 일 목록
- 캐시 관리 컨트롤: 개별 또는 전체 캐시 지우기
- 성능 비교: 바닐라 React vs React Query 패턴 나란히 비교
- 프레임워크: Next.js 15 with App Router
- 언어: TypeScript with strict mode
- UI 라이브러리: React 19
- 데이터 페칭: TanStack React Query + Axios
- 패키지 매니저: pnpm
- 개발 도구: ESLint, React Query DevTools
- Node.js 18.17+ 또는 20.3+
- pnpm (권장) 또는 npm/yarn
# 리포지토리 클론
git clone https://github.com/junh0328/localstorage-cache-example.git
cd localstorage-cache-example
# 의존성 설치
pnpm install
# 개발 서버 시작
pnpm dev바닐라 React 예제를 보려면 http://localhost:3000을, React Query 구현을 보려면 http://localhost:3000/react-query를 열어주세요.
pnpm dev # Turbopack으로 개발 서버 시작
pnpm build # 프로덕션 빌드 생성
pnpm start # 프로덕션 서버 시작
pnpm lint # ESLint 실행src/
├── util/
│ └── localStorageCache.ts # 핵심 캐싱 유틸리티
├── services/
│ └── apiService.ts # 캐시 통합이 포함된 API 레이어
├── hooks/
│ ├── useIsClient.ts # SSR 하이드레이션 훅
│ └── useReactQueryCache.ts # React Query + 캐시 훅
├── providers/
│ └── ReactQueryProvider.tsx # React Query 설정
└── app/
├── page.tsx # 바닐라 React 예제
└── react-query/
└── page.tsx # React Query 예제
// 격리된 저장소를 가진 서로 다른 캐시 인스턴스
const userCache = LocalStorageCache.getInstance('users', {
maxItemsPerKey: 50,
reset: { type: 'hourly', value: 0 },
});
const postsCache = LocalStorageCache.getInstance('posts', {
reset: { type: 'minutes', value: 15 },
});- 일일: 특정 UTC 시간에 리셋 (
{ type: 'daily', value: 2 }) - 시간별: 특정 분에 리셋 (
{ type: 'hourly', value: 30 }) - 분 단위: N분마다 리셋 (
{ type: 'minutes', value: 15 }) - 커스텀: 커스텀 리셋 함수 (
{ type: 'custom', customResetFn: fn })
- 항목 제한 초과 시 자동 LRU 제거
- 저장소 제한 도달 시 크기 기반 정리
- 네임스페이스별 설정 가능한 제한
import { LocalStorageCache } from '@/util/localStorageCache';
// 캐시 인스턴스 생성
const cache = LocalStorageCache.getInstance('my-app', {
maxItemsPerKey: 100,
maxTotalSize: 5 * 1024 * 1024, // 5MB
reset: { type: 'daily', value: 1 }, // 매일 UTC 1:00에 리셋
});
// 데이터 저장
cache.set('user-123', userData);
// 데이터 조회
const user = cache.get<User>('user-123');
// 특정 데이터 지우기
cache.clearByQueryKey('user');
// 캐시 통계 가져오기
const status = cache.getStatus();import { useUsers, useClearCache } from '@/hooks/useReactQueryCache';
function UserComponent() {
const { data: users, isLoading, error } = useUsers();
const clearCache = useClearCache();
const handleClearUsers = () => {
clearCache.mutate('users');
};
if (isLoading) return <div>로딩 중...</div>;
if (error) return <div>오류: {error.message}</div>;
return (
<div>
{users?.map((user) => (
<div key={user.id}>{user.name}</div>
))}
<button onClick={handleClearUsers}>캐시 지우기</button>
</div>
);
}# 선택사항: 캐시 동작 커스터마이징
CACHE_SIZE=4194304 # 기본 캐시 크기 (바이트)
NODE_ENV=development # React Query DevTools 활성화interface CacheConfig {
namespace: string; // 필수: 고유 식별자
maxItemsPerKey?: number; // 쿼리 키당 최대 항목 수
maxTotalSize?: number; // 전체 최대 캐시 크기 (바이트)
reset?: {
type: 'daily' | 'hourly' | 'minutes' | 'custom';
value?: number; // 시간/분/간격
customResetFn?: (timestamp: string) => Date;
};
}- 데이터 로드: 페치 버튼을 클릭하여 캐시 채우기
- 캐시 히트 확인: 후속 클릭은 캐시에서 즉시 로드되어야 함
- 저장소 모니터링: 브라우저 DevTools → Application → Local Storage 확인
- 만료 테스트: 리셋 시간 대기 또는 수동으로 캐시 지우기
- 성능 비교: 바닐라와 React Query 예제 간 전환
- 브라우저 DevTools: 네임스페이스 접두사가 있는 localStorage 키 검사
- 콘솔 로그: 캐시 히트 vs API 호출이 로깅됨
- 네트워크 탭: 캐시 히트 시 감소된 네트워크 요청 확인
- React Query DevTools: 쿼리 상태 및 캐시 무효화 모니터링
- 프로덕션 빌드는 React Query DevTools 제외
- LocalStorageCache 유틸리티는 경량 (~15KB 압축)
- 비필수 캐시 인스턴스에 대한 지연 로딩 고려
- 전체 캐시 크기 제한 모니터링
- 적절한 maxItemsPerKey 값 사용
- 중요한 데이터에 대한 캐시 워밍 전략 고려
- 적절한 stale-while-revalidate 패턴 구현
- React Query의 백그라운드 리페칭 사용
- 사용자 상호작용 시 프리페칭 고려
- 리포지토리 포크
- 기능 브랜치 생성 (
git checkout -b feature/amazing-feature) - 변경사항 커밋 (
git commit -m 'Add amazing feature') - 브랜치에 푸시 (
git push origin feature/amazing-feature) - Pull Request 열기
이 프로젝트는 MIT 라이선스 하에 있습니다 - 자세한 내용은 LICENSE 파일을 참조하세요.
- 데모 API를 위한 JSONPlaceholder
- 훌륭한 데이터 페칭 패턴을 위한 TanStack Query
- 견고한 React 프레임워크를 위한 Next.js
