99

최근 30분간 동시 방문자 수를 표시합니다. (~)

최고 동시 방문자 수 -
어제: 0명 / 오늘: 0명

Zustand Persist Middleware(스토리지 사용)의 선택 옵션 정리

ReactZustand
2년 전
33K
0
0

Zustand의 Persist 미들웨어에서 사용할 수 있는 선택 옵션들을 정리합니다.
name은 필수 옵션입니다.

모든 옵션은 다음 예제를 기준으로 설명합니다.

/src/store/count.ts
TS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { create } from 'zustand' import { combine, persist } from 'zustand/middleware' export const useCountStore = create( persist( combine( { count: 0, double: 0 }, set => ({ increase: () => set(state => ({ count: state.count + 1 })) }) ), { name: 'count' } ) )

Zustand의 전반적인 사용 방법은 Zustand 핵심 정리를 참고하세요!

# storage

기본의 로컬 스토리지(localStorage)가 아닌 세션 스토리지나 IndexedDB 등의 다른 스토리지를 사용할 수 있습니다.
만약 새로운 나만의 스토리지를 원하면, StateStorage 인터페이스와 일치하는 객체를 createJSONStorage 헬퍼 함수를 통해 반환하면 됩니다.

/node_modules/zustand/esm/middleware/persist.d.mts
TS
1
2
3
4
5
export interface StateStorage { getItem: (name: string) => string | null | Promise<string | null>; setItem: (name: string, value: string) => unknown | Promise<unknown>; removeItem: (name: string) => unknown | Promise<unknown>; }
StateStorage 인터페이스
/src/store/count.ts
TS
1
2
3
4
5
6
7
8
9
10
// ... export const useCountStore = create( persist( // combine(), { name: 'count', storage: createJSONStorage(() => sessionStorage) // 세션 스토리지 사용 } ) )

# Partialize

모든 상태를 스토리지에 저장하지 않고 원하는 상태만 저장하려면, partialize 옵션을 사용해 저장할 상태만 포함하는 객체를 반환합니다.
팩토리 함수이므로 저장 시 상태를 가공할 수 있지만, 리하이드레이션(Rehydration) 전까지는 현재 상태(currentState)와 스토리지 상태(persistedState)가 다를 수 있습니다.
하이드레이션에 대해서는 다음 옵션에서 설명합니다.

/src/store/count.ts
TS
1
2
3
4
5
6
7
8
9
10
11
12
// ... export const useCountStore = create( persist( // combine(), { name: 'count', partialize: currentState => ({ count: currentState.count // count 속성만 스토리지에 저장! }) } ) )

# onRehydrateStorage

onRehydrateStorage 옵션은 스토리지가 하이드레이션(Hydration)되면 실행되는 함수입니다.
하이드레이션 직후에 처리해야 하는 로직을 작성할 수 있으며, onRehydrateStoragestate 매개변수는 액션을 포함합니다.

Zustand에서 하이드레이션(Hydration) 은 스토리지에 저장된 상태를 현재 상태와 병합하는 프로세스를 말합니다.
useCountStore.persist.rehydrate() 메소드를 통해 수동으로도 언제든지 다시 하이드레이션(Rehydration)할 수 있습니다.
스토리지 상태를 현재 상태로 병합한다고 이해하면 쉽습니다.

/src/store/count.ts
TS
1
2
3
4
5
6
7
8
9
10
11
12
// ... export const useCountStore = create( persist( // combine(), { name: 'count', onRehydrateStorage: state => { console.log('스토리지 상태와 병합 완료!', state) } } ) )

# skipHydration

skipHydration 옵션을 사용해 최초 하이드레이션을 건너뛸 수 있습니다.
useCountStore.persist.rehydrate() 메소드를 통해 수동으로 리하이드레이션 할 수 있습니다.

/src/store/count.ts
TS
1
2
3
4
5
6
7
8
9
10
// ... export const useCountStore = create( persist( // combine(), { name: 'count', skipHydration: true } ) )
스토리지 상태를 하이드레이션 하지 않음.
/src/components/RehydrateButton.tsx
TSX
1
2
3
4
5
6
7
8
9
import { useCountStore } from './store/count' export default function RehydrateCountStore() { return ( <button onClick={() => useCountStore.persist.rehydrate()}> Rehydrate! </button> ) }
버튼을 선택해 하이드레이션.

# version

이미 스토리지에 저장된 데이터와 크게 다른 변경 사항을 도입하는 경우, 새로운 버전을 숫자로 지정해서 버전이 일치하지 않는 스토리지 데이터가 사용되지 않도록 할 수 있습니다.
만약 기존 버전을 무시하는 것이 아니라 활용해야 한다면, 다음에 설명하는 migrate 옵션을 사용할 수도 있습니다.

/src/store/count.ts
TS
1
2
3
4
5
6
7
8
9
10
// ... export const useCountStore = create( persist( // combine(), { name: 'count', version: 1 // 기본값: 0 } ) )

# migrate

하이드레이션 될 때 현재 상태의 버전이 스토리지의 버전과 다른 경우에 migrate 함수가 실행됩니다.
함수는 최신 버전과 일치하는 타입의 상태를 반환해야 하며, 스토리지의 데이터를 활용해야 하나 구조나 이름이 변경되었을 때 유용합니다.

/src/store/count.ts
TS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import { create } from 'zustand' import { combine, persist } from 'zustand/middleware' interface StateVersion0 { count: number double: number } interface StateVersion1 { amount: number multiplier: number max: number } export const useCountStore = create( persist( combine( { amount: 0, multiplier: 0 }, set => ({ increase: () => set(state => ({ amount: state.amount + 1 })) }) ), { name: 'count', version: 1, migrate: (persistedState, version) => { if (version === 0) { const oldState = persistedState as StateVersion0 const newState: StateVersion1 = { amount: oldState.count, multiplier: oldState.double, max: 100 } return newState } return persistedState } } ) )

# merge

merge 옵션은 하이드레이션 될 때 스토리지 상태를 현재 상태와 병합하는 방식을 지정할 수 있습니다.
기본적으로 스토리지와 현재의 상태는 얕은 병합(Shallow Merge)이 이뤄지지만, 깊은 병합(Deep Merge)이 필요한 경우 Lodash의 merge 함수를 사용할 수 있습니다.
migrate 함수보다 나중에 실행되며(두 옵션 모두 지정한 경우), migrate 함수가 반환하는 값을 첫 번째 매개변수(persistedState)로 받습니다.

BASH
1
2
npm i lodash-es npm i -D @types/lodash-es
깊은 병합이 필요한 경우 Lodash 설치
/src/store/count.ts
TS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ... import { merge } from 'lodash-es' export const useCountStore = create( persist( // combine(), { name: 'count', merge: (persistedState, currentState) => { return merge(currentState, persistedState) // 현재 상태와 스토리지 상태를 깊은 병합 } } ) )