AI 설문 선택 응답에 관련된 상태를 관리하기 위해 전역 상태의 타입을 다음과 같이 정의하였다.
// optionalSurvey.store.ts
interface OptionalSurveyState {
transportation: string[]; // 교통수단
preferTravelPurpose: string[]; // 선호하는 여행 목적
nonPreferTravelPurpose: string[]; // 비선호하는 여행 목적
preferAccommodation: string[]; // 선호하는 숙박 시설
nonPreferAccommodation: string[]; // 비선호하는 숙박 시설
preferRestaurant: string[]; // 선호하는 식당 유형
nonPreferRestaurant: string[]; // 비선호하는 식당 유형
setTransportation: (transportation: string[]) => void; // 교통수단 설정
setPreferTravelPurpose: (purpose: string[]) => void; // 선호하는 여행 목적 설정
setNonPreferTravelPurpose: (purpose: string[]) => void; // 비선호하는 여행 목적 설정
setPreferAccommodation: (accommodation: string[]) => void; // 선호하는 숙박 시설 설정
setNonPreferAccommodation: (accommodation: string[]) => void; // 비선호하는 숙박 시설 설정
setPreferRestaurant: (restaurant: string[]) => void; // 선호하는 식당 유형 설정
setNonPreferRestaurant: (restaurant: string[]) => void; // 비선호하는 식당 유형 설정
}
Zustand를 이용하여 useSurveyStore 안에 set 함수를 모두 다음과 같은 형식으로 정의하였다.
setTransportation: (transportation: string[]) => set({ transportation });
그 후에 다른 파일에서 다음과 같이 사용하였더니 에러가 발생하였다.
setTransportation((prev: string[]) => [...prev, buttonName]);
에러
Argument of type '(prev: string[]) => string[]' is not assignable to parameter of type 'string[]'.
에러 원인 분석
setTransportation의 타입은 현재 다음과 같이 정의되어 있음
setTransportation: (transportation: string[]) => void;
➡️ 즉, string[] 값 그 자체를 받도록 되어 있음
그런데 사용한 코드는
setTransportation((prev: string[]) => [...prev, buttonName]);
setTransportation에 함수를 인자로 넘기고 있음prev => [...prev, buttonName]은 함수인데, 타입 정의에서는 string[]만 받을 수 있도록 해놨기 때문에 타입 에러가 발생함에러 해결 방법
setTransportation이 string[]만 받도록 정의되어 있으니, getState() 함수를 이용하여 이전 상태를 직접 가져와서 처리해야 함
const current = useSurveyStore.getState().transportation;
setTransportation([...current, buttonName]);
➡️ 이렇게 하면 prev 함수 없이도 같은 효과를 얻을 수 있음
getState()란?Zustand에서 만든 store 객체가 가지고 있는 메서드 중 하나로, 현재 store의 상태(state) 값을 직접 가져오는 함수
컴포넌트 외부나 이벤트 리스너 같은 React의 리렌더링 흐름과 무관한 코드에서 상태 값을 읽을 때 사용됨
사용 예시
const current = useSurveyStore.getState().transportation;
이 코드는 다음과 같은 일을 함
useSurveyStore.getState() : 현재 store의 전체 상태 객체를 가져옴.transportation : 그 상태 중 transportation 값만 꺼냄getState() 사용 상황store 상태를 함수 바깥에서 조회할 때
Zustand의 hook(useSurveyStore)은 리액트 컴포넌트 내부에서만 사용 가능하지만, getState()는 컴포넌트 외부나 이벤트 핸들러, 비동기 로직 안에서도 사용할 수 있음
const handleClick = () => {
const prev = useSurveyStore.getState().transportation;
useSurveyStore.getState().setTransportation([...prev, "택시"]);
};
이전 상태를 기반으로 업데이트 할 때
Zustand는 set()에 이전 상태를 함수형으로 넘겨줄 수 있지만, setter가 값만 받도록 만들어졌다면 이렇게 해야 함
const prev = useSurveyStore.getState().transportation;
setTransportation([...prev, newValue]);
getState() 함수 주의사항getState()는 현재 상태를 한 번만 가져옴
➡️ 따라서 이 값을 계속 감지하거나 반응하려면 useSurveyStore((state) => state.xxx) 같은 훅을 써야 함
상태가 변경되어도 getState()는 자동으로 반응하지 않음
➡️ 리렌더링과는 관련이 없음
React의 useState나 useSurveyStore(state => ...)처럼 hook을 쓰면?
const transportation = useSurveyStore((state) => state.transportation);
transportation 값이 바뀌면 컴포넌트가 자동으로 리렌더링됨useSurveyStore.getState()는?
const current = useSurveyStore.getState().transportation;
get() vs. getState()get() : 스토어 생성 함수 내에서 사용하는 함수
export const useStore = create(
(set, get) => ({
someValue: 0,
increment: () => {
const current = get().someValue;
set({ someValue: current + 1});
},
})
);
get()은 스토어 생성 함수의 인자로 주어지는 함수임useStore)이 아직 만들어지기 전이므로, get()을 이용해서 현재 상태를 참조함create(...)() 안에서만 사용할 수 있음getState() : 만들어진 스토어 객체에서 직접 사용하는 메서드
const state = useStore.getState();
console.log(state.someValue);
getState()는 useStore 훅 객체가 가진 메서드임
리액트 컴포넌트 바깥(예: 유틸 파일, 이벤트 리스너, 외부 모듈)에서 상태를 동기적으로 직접 가져오고 싶을 때 사용함
useStore.getState()를 쓰면 현재 저장된 스토어의 전체 상태를 즉시 반환함
[주의] getState()는 create()가 반환하는 store 객체의 메서드라서 store가 생성되기 전에는 사용할 수 없음
➡️ 즉, create(...)() 안에서는 사용할 수 없음
[주의] useStore.state.someValue처럼 직접 접근하는 건 불가능함
❓
useStore의 정체는 무엇인가?const useStore = create(...);이렇게 만든
useStore는 사실 다음과 같은 훅(hook)이자 함수 객체임
useStore(): 컴포넌트 안에서 Reack Hook처럼 사용useStore.getState(): 현재 상태 동기 접근useStore.setState(): 외부에서 상태 직접 변경useStore.subscribe(): 외부에서 상태 구독즉,
useStore는 상태를 관리하는 특수한 함수 객체이며,state라는 직접 속성은 존재하지 않음
🤔
useStore.state.someValue는 어떻게 되나?console.log(useStore.state.someValue);
- 컴파일은 될 수도 있지만,
- 런타임에서
undefined오류가 남 →state라는 속성은useStore객체에 존재하지 않기 때문임
❓ 상태를 정확히 가져오려면?
반드시 이렇게 해야 함
const state = useStore.getState(); console.log(state.someValue);또는 리액트 컴포넌트 안에서 사용할 경우에는, 다음과 같이 해도 됨
const someValue = useStore((state) => state.someValue);
표로 비교하기
| 구분 | get() | getState() |
|---|---|---|
| 사용 위치 | create() 안에서만 사용 가능 | 어디서든 사용 가능 (컴포넌트 밖 등) |
| 용도 | 스토어 초기 생성 시 현재 상태 참조 | 현재 스토어 상태 동기적으로 가져오기 |
| 인자로 받는가 | (set, get) => ({ ... }) 형태로 받음 | useStore.getState()처럼 메서드 형태 |
| 예시 | get().someValue | useStore.getState().someValue |