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 라이센스를 따릅니다.