포스트

Zustand 슬라이스 패턴 (Slice Pattern)

Zustand 슬라이스 패턴 (Slice Pattern)

Zustand 슬라이스 패턴

정의

  • 애플리케이션의 규모가 커짐에 따라 하나의 거대한 스토어를 기능이나 도메인별로 작은 조각(Slice)으로 나누어 관리하는 설계 방식
  • 개별적으로 정의된 슬라이스들을 최종적으로 하나의 메인 스토어로 합성하여 사용한다.

특징

  • 관심사 분리 (Separation of Concerns)
    • 유저 정보, 게시글 목록, 설정값 등 서로 다른 성격의 상태를 별도의 파일이나 함수로 분리할 수 있다.
  • 결합성 (Composability)
    • 독립적인 슬라이스들을 결합하여 하나의 통합된 스토어를 구성한다.
  • 타입 안전성 (TypeScript 지원)
    • StateCreator 타입을 활용하여 각 슬라이스가 전체 스토어의 구조를 인지하면서도 독립적으로 정의될 수 있게 한다.

장점

  • 코드 가독성이 좋아지고 특정 기능을 수정할 때 관련 슬라이스만 확인하면 되므로 유지보수가 편리하다.
  • 여러 개발자가 서로 다른 슬라이스를 동시에 작업할 수 있어 협업에 유리하다.
  • 스토어 파일 하나가 수천 줄이 되는 ‘Fat Store’ 현상을 방지할 수 있다.

단점

  • 단순한 스토어 구조에 비해 초기 설정 코드가 다소 늘어날 수 있다.
  • 슬라이스 간에 상태를 공유하거나 서로의 액션을 호출해야 할 때 설계가 복잡해질 수 있다.

구현 방법 (TypeScript 기준)

1. 개별 슬라이스 정의

각 슬라이스는 StateCreator 타입을 사용하여 정의한다. 이때 첫 번째 제네릭 인자는 전체 스토어의 타입을 의미한다.

import { StateCreator } from 'zustand';

interface BearSlice {
  bears: number;
  addBear: () => void;
}

export const createBearSlice: StateCreator<
  BearSlice & FishSlice,
  [],
  [],
  BearSlice
> = (set) => ({
  bears: 0,
  addBear: () => set((state) => ({ bears: state.bears + 1 })),
});
interface FishSlice {
  fishes: number;
  addFish: () => void;
}

export const createFishSlice: StateCreator<
  BearSlice & FishSlice,
  [],
  [],
  FishSlice
> = (set) => ({
  fishes: 0,
  addFish: () => set((state) => ({ fishes: state.fishes + 1 })),
});

2. 슬라이스 합성 및 스토어 생성

정의된 슬라이스 생성 함수들을 하나의 create 함수 내에서 호출하여 병합한다.

import { create } from 'zustand';

type FullStoreState = BearSlice & FishSlice;

export const useBoundStore = create<FullStoreState>()((...a) => ({
  ...createBearSlice(...a),
  ...createFishSlice(...a),
}));

설계 팁

  • 슬라이스 간 참조: get() 함수를 통해 다른 슬라이스의 상태를 참조할 수 있지만, 지나친 의존성은 슬라이스 분리의 의미를 퇴색시킬 수 있으므로 주의해야 한다.
  • 파일 분리: 프로젝트의 store/ 디렉토리 아래에 bearsSlice.ts, fishesSlice.ts와 같이 파일을 나누고 index.ts에서 이를 통합하는 구조를 추천한다.
  • 타입 정의: 전체 스토어의 타입을 나타내는 인터페이스를 별도로 관리하면 순환 참조 문제를 예방하는 데 도움이 된다.

결론

슬라이스 패턴은 Zustand를 대규모 프로젝트에서 사용하기 위한 필수적인 전략이다. 스토어를 논리적인 단위로 쪼개어 관리함으로써 코드의 복잡도를 낮추고 개발 생산성을 크게 높일 수 있다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.