React용 최소 기능 전역 상태 관리 라이브러리
유효준
Frontend 개발자
JF002 - Minimal Global State Managment Library 구현
2025.10.24 (금)
약 6시간 (순수 작업 시간 기준, 휴식 및 개인 사유 제외)
개발 도구:
- IDE: IntelliJ IDEA
- AI Agent: Claude Code (Sonnet 4.5), ChatGPT (GPT-4)
- Package Manager: pnpm 10
- Node.js: v22.15.1
참조 문서:
- React: https://github.com/facebook/react
- Jotai: https://jotai.org/
핵심 기능:
- Atom 생성 및 관리 (
createAtom,get,set) - 구독 시스템 (
subscribe/unsubscribe) - React 통합 (
useAtomwithuseSyncExternalStore) - 값 비교 (
Object.is사용) - 메모리 관리 (GC-friendly cleanup - listeners null 처리)
- 자동 배치 업데이트 (React 18 자동 배칭 활용)
선택 기능:
- 파생 Atom (
createDerivedAtom,getDerived) - 비동기 Atom (
createAsyncAtom,getAsync,useAsyncAtomValue) - 배치 업데이트 (React 18 자동 배칭 활용)
- 메모리 최적화 (listeners null 처리)
- Frameworkless 사용 (예 - vue.js ) 에서도
get,set,subscribe만으로 상태 관리 가능
minimal-global-state/
├── packages/
│ ├── lib/ # 핵심 라이브러리
│ │ ├── src/
│ │ │ ├── core/ # 핵심 로직
│ │ │ │ ├── atom.ts
│ │ │ │ ├── atom.test.ts
│ │ │ │ ├── subscribe.ts
│ │ │ │ ├── subscribe.test.ts
│ │ │ │ ├── derived.ts
│ │ │ │ ├── derived.test.ts
│ │ │ │ ├── async.ts
│ │ │ │ └── async.test.ts
│ │ │ ├── react/ # React 통합
│ │ │ │ ├── useAtom.ts
│ │ │ │ ├── useAtom.test.tsx
│ │ │ │ └── useAsyncAtomValue.ts
│ │ │ ├── vue/ # Vue 통합
│ │ │ │ ├── useAtom.ts
│ │ │ │ ├── useAtom.test.ts
│ │ │ │ └── index.ts
│ │ │ ├── types/ # 타입 정의
│ │ │ │ └── index.ts
│ │ │ ├── index.ts # 공개 API
│ │ │ └── test-setup.ts # 테스트 설정
│ │ ├── dist/ # 빌드 결과물
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ ├── vite.config.ts
│ │ └── vitest.config.ts
│ ├── react/ # React 데모 앱
│ │ ├── src/
│ │ │ ├── examples/ # 예제 컴포넌트
│ │ │ │ ├── basic/ # 기본 사용 예제
│ │ │ │ │ ├── display-1.tsx
│ │ │ │ │ ├── display-2.tsx
│ │ │ │ │ ├── display-3.tsx
│ │ │ │ │ ├── display-4.tsx
│ │ │ │ │ └── editor.tsx
│ │ │ │ ├── async/ # 비동기 Atom 예제
│ │ │ │ │ └── async-data.tsx
│ │ │ │ ├── create-derived/ # 파생 Atom 예제
│ │ │ │ │ └── derived-state.tsx
│ │ │ │ ├── batch/ # 배치 업데이트 예제
│ │ │ │ │ └── batch-update.tsx
│ │ │ │ ├── multi-component.tsx # 멀티 컴포넌트 예제 (기본 예제)
│ │ │ │ └── shared.ts # 공유 Atom 정의
│ │ │ ├── app.tsx
│ │ │ ├── index.tsx
│ │ │ └── vite-env.d.ts
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
│ └── vue/ # Vue 데모 앱
│ ├── src/
│ │ ├── components/ # Vue 컴포넌트
│ │ │ ├── counter-display.vue
│ │ │ ├── counter-buttons.vue
│ │ │ └── counter-reset.vue
│ │ ├── store/ # 전역 상태
│ │ │ └── atoms.ts
│ │ ├── app.vue
│ │ ├── main.ts
│ │ └── vite-env.d.ts
│ ├── index.html
│ ├── package.json
│ ├── tsconfig.json
│ └── vite.config.ts
├── docs/
│ └── DESIGN.md # 설계 문서
├── detail-plan.md # 상세 구현 계획
├── advanced-detail-plan.md # 고급 기능 구현 계획
├── .claude/ # Claude Code 설정
├── .eslintrc.json # ESLint 설정
├── .prettierrc # Prettier 설정
├── package.json # 워크스페이스 설정
├── pnpm-workspace.yaml # Monorepo 설정
├── tsconfig.json # 공통 TypeScript 설정
└── README.md # 본 문서
# 설치 및 빌드
pnpm install
pnpm build
# React 데모 실행
pnpm dev:react
# Vue 데모 실행
pnpm dev:vue
# 테스트
pnpm test런타임 의존성:
- React 18.0.0+ (peer dependency): React 프레임워크 지원
개발 의존성:
- TypeScript 5.3.3: 정적 타입 검사
- Vite 5.0.12: 빌드 도구 - 빠른 빌드 속도와 ESM 지원
- vite-plugin-dts 4.5.4: TypeScript 선언 파일 자동 생성
- Vitest 1.2.2: 테스트 프레임워크 - Vite 기반의 빠른 테스트 실행
- @testing-library/react 14.1.2: React 컴포넌트 테스트 - 사용자 중심 테스트 작성
- @vitest/coverage-v8 1.2.2: 코드 커버리지 측정
- jsdom 24.0.0: DOM 환경 시뮬레이션 - 브라우저 없이 테스트 실행
런타임 의존성:
- @minimal-state/lib: workspace 내부 라이브러리
- React 18.2.0: UI 라이브러리
- React-DOM 18.2.0: React DOM 렌더러
개발 의존성:
- Vite 5.0.12: 개발 서버 및 빌드 도구
- @vitejs/plugin-react 4.2.1: React 플러그인 - Fast Refresh 지원
코드 품질 도구:
- ESLint 8.57.0: 코드 린팅 - 코드 품질 검사
- @typescript-eslint/eslint-plugin 6.21.0: TypeScript ESLint 플러그인
- @typescript-eslint/parser 6.21.0: TypeScript 파서
- eslint-plugin-react 7.33.2: React ESLint 규칙
- eslint-plugin-react-hooks 4.6.0: React Hooks 규칙
- Prettier 3.2.4: 코드 포맷팅 - 일관된 코드 스타일
- 난이도: 적절함
- 소요 시간: 적절함
- 평가: 상태 관리 라이브러리의 내부 구현 원리를 생각 해볼 수 있는 좋은 학습 기회였다고 생각합니다
시간이 충분했다면 다음 기능들을 추가로 구현해볼 수 있었을 것 같습니다:
-
Atom Family
- 동적으로 여러 atom을 생성하고 관리하는 패턴
- 예:
atomFamily((id) => createAtom(...))
-
Atom with Storage
- localStorage/sessionStorage와 자동 동기화
- 페이지 새로고침 시 상태 복원
-
DevTools
- 브라우저 확장 프로그램으로 atom 상태 시각화
- Time-travel debugging 지원
import { createAtom, useAtom } from '@minimal-state/lib';
// 1. Atom 생성
const countAtom = createAtom(0);
// 2. React 컴포넌트에서 사용
function Counter() {
const [count, setCount] = useAtom(countAtom);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}import { createAtom, get, set, subscribe } from '@minimal-state/lib';
const atom = createAtom(0);
// 값 읽기
console.log(get(atom)); // 0
// 값 쓰기
set(atom, 1);
// 구독
const unsubscribe = subscribe(atom, (value) => {
console.log('Value changed:', value);
});
// 구독 해제
unsubscribe();import { createAtom, createDerivedAtom, useAtom } from '@minimal-state/lib';
const firstNameAtom = createAtom('John');
const lastNameAtom = createAtom('Doe');
// 파생 atom 생성
const fullNameAtom = createDerivedAtom((get) => {
return `${get(firstNameAtom)} ${get(lastNameAtom)}`;
});
function FullName() {
const [fullName] = useAtom(fullNameAtom);
return <p>{fullName}</p>; // "John Doe"
}import { createAsyncAtom, useAsyncAtomValue } from '@minimal-state/lib';
import { Suspense } from 'react';
// 비동기 atom 생성
const userAtom = createAsyncAtom(async () => {
const response = await fetch('/api/user');
return response.json();
});
function UserProfile() {
const user = useAsyncAtomValue(userAtom);
return <div>Name: {user.name}</div>;
}
// Suspense로 감싸서 사용
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<UserProfile />
</Suspense>
);
}- 설계 문서 - 아키텍처 및 설계 결정
- 상세 구현 계획 - 단계별 구현 계획 및 작업 내역
- 고급 기능 구현 계획 - 고급 기능 상세 설계 및 구현 계획
- CLAUDE.md - AI 에이전트용 프로젝트 설명
MIT