Skip to content

restareaByWeezy/react-batcher

Repository files navigation

React Batcher

React에서 API 요청을 배치로 처리하고 외부 store와 동기화하는 라이브러리입니다. useSyncExternalStore를 사용하여 React 18+와 완벽하게 호환됩니다.

특징

  • 🚀 배치 처리: 여러 개별 요청을 하나의 배치 요청으로 합쳐서 처리
  • 🔄 Store 통합: Zustand, Redux 등 다양한 상태 관리 라이브러리와 호환
  • 성능 최적화: 중복 요청 제거 및 지능적인 캐싱
  • 🎯 TypeScript 지원: 완전한 타입 안정성
  • 🪝 React Hooks: 간편한 React 통합
  • 🛠️ 커스터마이징: 버퍼 시간, 배치 크기 등 설정 가능
  • 💾 상태 영속성: localStorage/sessionStorage를 통한 상태 저장

설치

npm install react-batcher
# 또는
yarn add react-batcher
# 또는
pnpm add react-batcher

목차

  1. 기본 사용법
  2. Export 목록
  3. 타입 정의
  4. BatchManager 클래스
  5. React Hooks
  6. Store 어댑터
  7. 유틸리티 함수
  8. 고급 사용법

기본 사용법

1. 타입 정의

import { BatchableItem } from 'react-batcher';

// 모든 아이템은 반드시 id 필드를 가져야 합니다
interface User extends BatchableItem {
  id: string;
  name: string;
  email: string;
  avatar?: string;
}

2. Store 설정 (Zustand 예제)

import { create } from 'zustand';
import { BatchManager, createSimpleZustandAdapter } from 'react-batcher';

// Zustand store 생성
const useUserStore = create<Record<string, User>>(() => ({}));

// Store 어댑터 생성
const userStoreAdapter = createSimpleZustandAdapter({
  getState: useUserStore.getState,
  setState: useUserStore.setState,
  subscribe: useUserStore.subscribe,
});

3. API 함수 정의

// BatchFetcher 타입: (ids: string[]) => Promise<T[]>
async function fetchBatchUsers(userIds: string[]): Promise<User[]> {
  const response = await fetch('/api/batch-users', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ userIds }),
  });

  const data = await response.json();
  return data.users;
}

4. BatchManager 생성

export const userBatchManager = new BatchManager<User>({
  store: userStoreAdapter,
  fetcher: fetchBatchUsers,
  bufferConfig: {
    delayMs: 100, // 100ms 대기 후 배치 처리
    maxBatchSize: 50, // 최대 50개씩 배치 처리
  },
  debug: true,
  onError: (error, failedIds) => {
    console.error('Failed to fetch users:', error, failedIds);
  },
});

5. React 컴포넌트에서 사용

import { useBatchedItem } from "react-batcher";

function UserProfile({ userId }: { userId: string }) {
  const user = useBatchedItem(userBatchManager, userId);

  if (!user) {
    return <div>Loading user...</div>;
  }

  return (
    <div>
      <img src={user.avatar} alt={user.name} />
      <h3>{user.name}</h3>
      <p>{user.email}</p>
    </div>
  );
}

Export 목록

// 메인 클래스
export { BatchManager } from './BatchManager';

// 타입 정의
export type {
  BatchableItem,
  Store,
  BatchFetcher,
  BufferConfig,
  BatchManagerConfig,
  BatchManagerState,
} from './types';

// React 훅
export {
  useBatchedItem,
  useBatchedItems,
  useAllBatchedItems,
  usePreloadItems,
  useFlushBatch,
  useBatchManagerState,
  useBatchedState,
  useBatchStats,
} from './hooks';

// Store 어댑터
export {
  createZustandAdapter,
  createSimpleZustandAdapter,
} from './adapters/zustand';
export { createReduxAdapter } from './adapters/redux';
export { createMemoryStore } from './adapters/memory';

// 유틸리티
export { createBuffer, type BufferInstance } from './buffer';
export {
  createPersistence,
  loadState,
  saveState,
  clearPersistedState,
  type PersistenceConfig,
} from './persistence';

타입 정의

BatchableItem

배치 처리할 데이터의 기본 인터페이스입니다. 모든 아이템은 반드시 고유한 id를 가져야 합니다.

interface BatchableItem {
  id: string;
}

// 사용 예시
interface User extends BatchableItem {
  id: string;
  name: string;
  email: string;
}

interface Product extends BatchableItem {
  id: string;
  title: string;
  price: number;
}

Store

외부 상태 관리 라이브러리와의 통합을 위한 추상화 인터페이스입니다.

interface Store<T extends BatchableItem> {
  // 현재 store의 상태를 가져오는 함수
  getState: () => Record<string, T>;

  // store 상태 변경을 구독하는 함수
  subscribe: (listener: () => void) => () => void;

  // store 상태를 업데이트하는 함수
  setState: (newState: Record<string, T>) => void;
}

BatchFetcher

API에서 배치로 데이터를 가져오는 함수 타입입니다.

type BatchFetcher<T extends BatchableItem> = (ids: string[]) => Promise<T[]>;

// 사용 예시
const fetchUsers: BatchFetcher<User> = async ids => {
  const response = await fetch('/api/users', {
    method: 'POST',
    body: JSON.stringify({ ids }),
  });
  return response.json();
};

BufferConfig

버퍼 설정 옵션입니다.

interface BufferConfig {
  // 배치 처리를 위한 대기 시간 (밀리초)
  // @default 100
  delayMs?: number;

  // 한 번에 처리할 최대 아이템 수
  // @default undefined (제한 없음)
  maxBatchSize?: number;
}

// 사용 예시
const config: BufferConfig = {
  delayMs: 50, // 50ms 대기
  maxBatchSize: 100, // 최대 100개씩 처리
};

RetryConfig

재시도 설정 옵션입니다.

interface RetryConfig {
  // 최대 재시도 횟수 @default 3
  maxRetries?: number;

  // 재시도 지연 시간 (밀리초) @default 1000
  retryDelay?: number;

  // 백오프 전략 @default 'exponential'
  // - linear: 고정 지연
  // - exponential: 지수적 증가
  backoff?: 'linear' | 'exponential';

  // 재시도 가능한 에러인지 판단하는 함수
  shouldRetry?: (error: Error, attempt: number) => boolean;
}

BatchManagerConfig

BatchManager 생성 시 사용하는 설정 옵션입니다.

interface BatchManagerConfig<T extends BatchableItem> {
  // [필수] 외부 store 인스턴스
  store: Store<T>;

  // [필수] 배치로 데이터를 가져오는 함수
  fetcher: BatchFetcher<T>;

  // [선택] 버퍼 설정
  bufferConfig?: BufferConfig;

  // [선택] 에러 발생 시 호출되는 콜백
  onError?: (error: Error, failedIds: string[]) => void;

  // [선택] 디버그 모드 활성화
  debug?: boolean;

  // [선택] 초기 상태
  initialState?: Partial<BatchManagerState>;

  // [선택] 재시도 설정
  retryConfig?: RetryConfig;

  // [선택] 상태 저장 키 (localStorage/sessionStorage에 저장)
  persistenceKey?: string;
}

BatchManagerState

BatchManager의 현재 상태를 나타내는 인터페이스입니다.

interface BatchManagerState {
  // 현재 상태
  // - idle: 대기 중
  // - pending: 버퍼에 아이템이 쌓이는 중
  // - processing: API 요청 실행 중
  status: 'idle' | 'pending' | 'processing';

  // 배치 실행 횟수
  executionCount: number;

  // 총 처리된 아이템 수
  totalItemsProcessed: number;

  // 버퍼가 비어있는지 여부
  isEmpty: boolean;

  // 대기 중인 아이템이 있는지 여부
  isPending: boolean;

  // 현재 버퍼 크기
  bufferSize: number;

  // 대기 중인 요청 개수
  pendingRequestCount: number;

  // 마지막 배치 실행 시각 (timestamp)
  lastExecutionTime: number | null;

  // 마지막 에러
  lastError: Error | null;
}

BatchManager 클래스

BatchManager는 API 요청을 배치로 모아서 효율적으로 처리하고, 외부 store와 동기화하는 핵심 클래스입니다.

생성자

const batchManager = new BatchManager<User>({
  store: userStoreAdapter,
  fetcher: fetchBatchUsers,
  bufferConfig: {
    delayMs: 100,
    maxBatchSize: 50,
  },
  debug: true,
  onError: (error, failedIds) => {
    console.error('Fetch failed:', error, failedIds);
  },
  persistenceKey: 'user-batch-state', // localStorage에 상태 저장
});

메서드

requestItem(id: string): T | null

아이템을 요청합니다. store에 있으면 즉시 반환하고, 없으면 배치 요청에 추가 후 null을 반환합니다.

const user = batchManager.requestItem('user-123');
if (user) {
  console.log('User found:', user.name);
} else {
  console.log('User is being fetched...');
}

getItem(id: string): T | null

store에서 아이템을 가져옵니다. 요청은 하지 않습니다.

// 이미 로드된 아이템만 가져오기 (API 호출 없음)
const user = batchManager.getItem('user-123');

preloadItems(ids: string[]): void

여러 아이템을 미리 로드합니다. 화면에 표시하기 전에 데이터를 미리 가져올 때 유용합니다.

// 페이지 진입 시 필요한 사용자들 미리 로드
batchManager.preloadItems(['user-1', 'user-2', 'user-3']);

flush(): Promise

대기 중인 모든 배치 요청을 즉시 처리합니다. 타임아웃을 기다리지 않습니다.

// 여러 아이템 요청 후 즉시 처리
batchManager.requestItem('user-1');
batchManager.requestItem('user-2');
batchManager.requestItem('user-3');
await batchManager.flush(); // 100ms 기다리지 않고 즉시 API 호출

// 페이지 떠나기 전에 대기 중인 요청 모두 처리
window.addEventListener('beforeunload', () => {
  batchManager.flush();
});

getAllItems(): Record<string, T>

store의 모든 아이템을 가져옵니다.

const allUsers = batchManager.getAllItems();
Object.values(allUsers).forEach(user => {
  console.log(user.name);
});

removeItem(id: string): void

특정 아이템을 store에서 제거합니다.

// 사용자 삭제 후 store에서도 제거
await deleteUser('user-123');
batchManager.removeItem('user-123');

clearAll(): void

store의 모든 아이템을 제거합니다.

// 로그아웃 시 모든 캐시 클리어
function handleLogout() {
  batchManager.clearAll();
}

getPendingCount(): number

현재 대기 중인 요청 개수를 반환합니다. (디버깅용)

console.log(`Pending requests: ${batchManager.getPendingCount()}`);

getBufferSize(): number

현재 버퍼에 대기 중인 아이템 수를 반환합니다.

console.log(`Buffer size: ${batchManager.getBufferSize()}`);

isBufferEmpty(): boolean

버퍼가 비어있는지 확인합니다.

if (batchManager.isBufferEmpty()) {
  console.log('No pending items');
}

getState(): BatchManagerState

BatchManager의 현재 상태를 반환합니다.

const state = batchManager.getState();
console.log(`Status: ${state.status}`);
console.log(`Execution count: ${state.executionCount}`);
console.log(`Total processed: ${state.totalItemsProcessed}`);

getStats()

통계 정보를 반환합니다.

const stats = batchManager.getStats();
console.log(`Execution count: ${stats.executionCount}`);
console.log(`Total items processed: ${stats.totalItemsProcessed}`);
console.log(`Average items per batch: ${stats.averageItemsPerBatch}`);
console.log(`Last execution: ${new Date(stats.lastExecutionTime)}`);
console.log(`Current buffer size: ${stats.currentBufferSize}`);
console.log(`Pending requests: ${stats.pendingRequestCount}`);

subscribe / getSnapshot (useSyncExternalStore용)

React의 useSyncExternalStore와 함께 사용하기 위한 메서드들입니다. 일반적으로 직접 사용하지 않고 제공되는 hooks를 사용합니다.

// 내부적으로 hooks에서 사용됨
const snapshot = useSyncExternalStore(
  batchManager.subscribe,
  batchManager.getSnapshot
);

subscribeState / getStateSnapshot

BatchManager 상태 변경을 구독하기 위한 메서드들입니다.

// 상태 변경 구독
const unsubscribe = batchManager.subscribeState(() => {
  console.log('State changed:', batchManager.getStateSnapshot());
});

// 구독 해제
unsubscribe();

React Hooks

useBatchedItem

단일 아이템을 가져오는 훅입니다. 아이템이 없으면 자동으로 배치 요청에 추가됩니다.

function useBatchedItem<T extends BatchableItem>(
  manager: BatchManager<T>,
  id: string
): T | null;

// 사용 예시
function UserCard({ userId }: { userId: string }) {
  const user = useBatchedItem(userBatchManager, userId);

  if (!user) {
    return <Skeleton />;
  }

  return (
    <div className="user-card">
      <img src={user.avatar} alt={user.name} />
      <h3>{user.name}</h3>
    </div>
  );
}

useBatchedItems

여러 아이템을 한 번에 가져오는 훅입니다.

function useBatchedItems<T extends BatchableItem>(
  manager: BatchManager<T>,
  ids: string[]
): (T | null)[];

// 사용 예시
function UserList({ userIds }: { userIds: string[] }) {
  const users = useBatchedItems(userBatchManager, userIds);

  return (
    <div className="user-list">
      {users.map((user, index) => (
        <div key={userIds[index]}>
          {user ? user.name : 'Loading...'}
        </div>
      ))}
    </div>
  );
}

useAllBatchedItems

store의 모든 아이템을 가져오는 훅입니다.

function useAllBatchedItems<T extends BatchableItem>(
  manager: BatchManager<T>
): Record<string, T>;

// 사용 예시
function AllUsers() {
  const allUsers = useAllBatchedItems(userBatchManager);

  return (
    <ul>
      {Object.values(allUsers).map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

usePreloadItems

아이템들을 미리 로드하는 훅입니다. ids가 변경될 때마다 자동으로 preload됩니다.

function usePreloadItems<T extends BatchableItem>(
  manager: BatchManager<T>,
  ids: string[]
): void;

// 사용 예시
function UserDashboard({ friendIds }: { friendIds: string[] }) {
  // 친구 목록을 미리 로드
  usePreloadItems(userBatchManager, friendIds);

  return (
    <div>
      <h1>Dashboard</h1>
      {/* 이후 UserCard에서 useBatchedItem 사용 시 이미 로드됨 */}
      {friendIds.map(id => (
        <UserCard key={id} userId={id} />
      ))}
    </div>
  );
}

useFlushBatch

배치를 수동으로 flush하는 함수를 반환하는 훅입니다.

function useFlushBatch<T extends BatchableItem>(
  manager: BatchManager<T>
): () => Promise<void>;

// 사용 예시
function SubmitForm() {
  const flushBatch = useFlushBatch(userBatchManager);

  const handleSubmit = async () => {
    // 폼 제출 전에 대기 중인 모든 요청 처리
    await flushBatch();
    submitForm();
  };

  return <button onClick={handleSubmit}>Submit</button>;
}

useBatchManagerState

BatchManager의 전체 상태를 구독하는 훅입니다.

function useBatchManagerState<T extends BatchableItem>(
  manager: BatchManager<T>
): BatchManagerState;

// 사용 예시
function BatchStatus() {
  const state = useBatchManagerState(userBatchManager);

  return (
    <div className="batch-status">
      <p>Status: {state.status}</p>
      <p>Pending: {state.isPending ? 'Yes' : 'No'}</p>
      <p>Buffer Size: {state.bufferSize}</p>
      <p>Executions: {state.executionCount}</p>
      <p>Total Processed: {state.totalItemsProcessed}</p>
      {state.lastError && (
        <p className="error">Error: {state.lastError.message}</p>
      )}
    </div>
  );
}

useBatchedState

BatchManager의 특정 상태만 선택적으로 구독하는 훅입니다. 불필요한 리렌더링을 방지합니다.

function useBatchedState<T extends BatchableItem, R>(
  manager: BatchManager<T>,
  selector: (state: BatchManagerState) => R
): R;

// 사용 예시
function LoadingIndicator() {
  // status만 구독하여 다른 상태 변경 시 리렌더링 방지
  const status = useBatchedState(
    userBatchManager,
    state => state.status
  );

  if (status === 'processing') {
    return <Spinner />;
  }
  return null;
}

function PendingBadge() {
  // isPending만 구독
  const isPending = useBatchedState(
    userBatchManager,
    state => state.isPending
  );

  return isPending ? <Badge>Loading...</Badge> : null;
}

// 여러 필드를 하나의 객체로 선택
function BatchInfo() {
  const info = useBatchedState(userBatchManager, state => ({
    count: state.executionCount,
    total: state.totalItemsProcessed
  }));

  return <p>Batches: {info.count}, Items: {info.total}</p>;
}

useBatchStats

BatchManager의 통계 정보를 구독하는 훅입니다.

function useBatchStats<T extends BatchableItem>(manager: BatchManager<T>): {
  executionCount: number;
  totalItemsProcessed: number;
  averageItemsPerBatch: number;
  lastExecutionTime: number | null;
};

// 사용 예시
function StatsDisplay() {
  const stats = useBatchStats(userBatchManager);

  return (
    <div className="stats">
      <p>Total batches: {stats.executionCount}</p>
      <p>Total items: {stats.totalItemsProcessed}</p>
      <p>Avg per batch: {stats.averageItemsPerBatch.toFixed(1)}</p>
      {stats.lastExecutionTime && (
        <p>Last run: {new Date(stats.lastExecutionTime).toLocaleString()}</p>
      )}
    </div>
  );
}

Store 어댑터

createMemoryStore

외부 라이브러리 없이 사용할 수 있는 간단한 인메모리 store입니다.

function createMemoryStore<T extends BatchableItem>(): Store<T>;

// 사용 예시
import { createMemoryStore, BatchManager } from 'react-batcher';

const store = createMemoryStore<User>();

const batchManager = new BatchManager<User>({
  store,
  fetcher: fetchBatchUsers,
});

createSimpleZustandAdapter

단순한 Zustand store를 위한 어댑터입니다. Store가 Record<string, T> 형태일 때 사용합니다.

function createSimpleZustandAdapter<T extends BatchableItem>(zustandStore: {
  getState: () => Record<string, T>;
  setState: (state: Record<string, T>) => void;
  subscribe: (listener: () => void) => () => void;
}): Store<T>;

// 사용 예시
import { create } from 'zustand';
import { createSimpleZustandAdapter } from 'react-batcher';

// 단순 형태의 Zustand store
const useUserStore = create<Record<string, User>>(() => ({}));

const userStoreAdapter = createSimpleZustandAdapter({
  getState: useUserStore.getState,
  setState: useUserStore.setState,
  subscribe: useUserStore.subscribe,
});

createZustandAdapter

items 필드로 래핑된 Zustand store를 위한 어댑터입니다.

function createZustandAdapter<T extends BatchableItem>(zustandStore: {
  getState: () => { items: Record<string, T> };
  setState: (partial: { items: Record<string, T> }) => void;
  subscribe: (listener: () => void) => () => void;
}): Store<T>;

// 사용 예시
interface UserStore {
  items: Record<string, User>;
  // 다른 상태들...
  filter: string;
}

const useUserStore = create<UserStore>(() => ({
  items: {},
  filter: '',
}));

const userStoreAdapter = createZustandAdapter({
  getState: useUserStore.getState,
  setState: useUserStore.setState,
  subscribe: useUserStore.subscribe,
});

createReduxAdapter

Redux store를 위한 어댑터입니다.

function createReduxAdapter<T extends BatchableItem>(
  reduxStore: {
    getState: () => any;
    dispatch: (action: any) => void;
    subscribe: (listener: () => void) => () => void;
  },
  selector: (state: any) => Record<string, T>,
  updateAction: (items: Record<string, T>) => any
): Store<T>;

// 사용 예시
import { createReduxAdapter } from 'react-batcher';
import { store } from './redux/store';

const userStoreAdapter = createReduxAdapter(
  store,
  // selector: Redux state에서 users 추출
  state => state.users.items,
  // action creator: 업데이트 액션 생성
  users => ({ type: 'users/setAll', payload: users })
);

// Redux Toolkit 사용 시
import { setUsers } from './redux/usersSlice';

const userStoreAdapter = createReduxAdapter(
  store,
  state => state.users,
  users => setUsers(users)
);

유틸리티 함수

createBuffer

여러 호출을 배치로 모아서 처리하는 버퍼 함수를 생성합니다. BatchManager 내부에서 사용되지만, 직접 사용할 수도 있습니다.

interface BufferInstance<T> {
  add: (item: T) => void; // 버퍼에 아이템 추가
  flush: () => Promise<void>; // 즉시 처리
  size: () => number; // 버퍼 크기
  isEmpty: () => boolean; // 비어있는지 확인
}

function createBuffer<T, R = void>(options: {
  ms: number; // 대기 시간
  subscribedFn: (items: T[]) => Promise<R>; // 배치 처리 함수
  maxBatchSize?: number; // 최대 배치 크기
}): BufferInstance<T>;

// 사용 예시: 로그 배치 전송
const logBuffer = createBuffer<LogEntry>({
  ms: 5000, // 5초마다
  maxBatchSize: 100, // 또는 100개 모이면
  subscribedFn: async logs => {
    await fetch('/api/logs', {
      method: 'POST',
      body: JSON.stringify(logs),
    });
  },
});

// 로그 추가
logBuffer.add({ level: 'info', message: 'User clicked button' });
logBuffer.add({ level: 'error', message: 'API failed' });

// 페이지 종료 시 즉시 전송
window.addEventListener('beforeunload', () => logBuffer.flush());

Persistence 함수들

상태를 localStorage/sessionStorage에 저장하고 불러오는 유틸리티입니다.

interface PersistenceConfig {
  key: string; // Storage key
  storage?: 'localStorage' | 'sessionStorage'; // @default 'localStorage'
  fields?: Array<keyof BatchManagerState>; // 저장할 필드들
  serialize?: (state: Partial<BatchManagerState>) => string;
  deserialize?: (data: string) => Partial<BatchManagerState>;
}

// 상태 불러오기
function loadState(
  config: PersistenceConfig
): Partial<BatchManagerState> | null;

// 상태 저장
function saveState(state: BatchManagerState, config: PersistenceConfig): void;

// 저장된 상태 삭제
function clearPersistedState(config: PersistenceConfig): void;

// 헬퍼 함수들 생성
function createPersistence(config: PersistenceConfig): {
  load: () => Partial<BatchManagerState> | null;
  save: (state: BatchManagerState) => void;
  clear: () => void;
};
// 사용 예시: 직접 persistence 사용
import {
  createPersistence,
  loadState,
  saveState,
  clearPersistedState,
} from 'react-batcher';

// 방법 1: createPersistence 사용
const persistence = createPersistence({
  key: 'my-batch-state',
  storage: 'localStorage',
  fields: ['executionCount', 'totalItemsProcessed'],
});

const savedState = persistence.load();
// ... 작업 후
persistence.save(currentState);
persistence.clear();

// 방법 2: 개별 함수 사용
const config = { key: 'my-batch-state' };
const state = loadState(config);
saveState(newState, config);
clearPersistedState(config);

// BatchManager에서 자동으로 사용
const batchManager = new BatchManager<User>({
  store,
  fetcher,
  persistenceKey: 'user-batch-state', // 자동으로 상태 저장/복원
});

고급 사용법

여러 BatchManager 사용

// users
const userBatchManager = new BatchManager<User>({
  store: createMemoryStore<User>(),
  fetcher: fetchBatchUsers,
});

// products
const productBatchManager = new BatchManager<Product>({
  store: createMemoryStore<Product>(),
  fetcher: fetchBatchProducts,
});

// 컴포넌트에서
function ProductWithSeller({ productId }: { productId: string }) {
  const product = useBatchedItem(productBatchManager, productId);
  const seller = useBatchedItem(userBatchManager, product?.sellerId ?? '');

  if (!product) return <Loading />;

  return (
    <div>
      <h2>{product.title}</h2>
      <p>Sold by: {seller?.name ?? 'Loading...'}</p>
    </div>
  );
}

에러 처리 패턴

const batchManager = new BatchManager<User>({
  store,
  fetcher,
  onError: (error, failedIds) => {
    // 에러 로깅
    console.error('Batch fetch failed:', error);

    // 사용자에게 알림
    toast.error(`Failed to load ${failedIds.length} users`);

    // 에러 추적 서비스에 전송
    Sentry.captureException(error, {
      extra: { failedIds },
    });
  },
});

// 컴포넌트에서 에러 상태 표시
function UserWithError({ userId }: { userId: string }) {
  const user = useBatchedItem(batchManager, userId);
  const { lastError } = useBatchManagerState(batchManager);

  if (lastError) {
    return <ErrorMessage error={lastError} />;
  }

  if (!user) {
    return <Skeleton />;
  }

  return <UserCard user={user} />;
}

조건부 로딩

function ConditionalUser({ userId, shouldLoad }: {
  userId: string;
  shouldLoad: boolean;
}) {
  // shouldLoad가 false면 빈 ID로 요청하지 않음
  const user = useBatchedItem(
    userBatchManager,
    shouldLoad ? userId : ''
  );

  if (!shouldLoad) {
    return <p>Click to load user</p>;
  }

  return user ? <UserCard user={user} /> : <Loading />;
}

캐시 무효화

// 특정 사용자 정보 갱신
async function refreshUser(userId: string) {
  // 기존 캐시 제거
  userBatchManager.removeItem(userId);

  // 다시 요청
  userBatchManager.requestItem(userId);
  await userBatchManager.flush();
}

// 전체 캐시 클리어
function clearAllCache() {
  userBatchManager.clearAll();
}

마이그레이션 가이드

기존 코드에서 이 라이브러리로 마이그레이션하는 방법:

Before (기존 코드)

const user = userStoreManager.requestUser(userId);
userStoreManager.preloadUsers(userIds);
const pendingCount = userStoreManager.getPendingCount();

After (라이브러리 사용)

const user = useBatchedItem(userBatchManager, userId);
userBatchManager.preloadItems(userIds);
const pendingCount = userBatchManager.getPendingCount();

라이센스

MIT

기여

이슈나 PR을 환영합니다!

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors