본격적으로 코드를 뚝딱이기 전에 프로젝트에서 React Query
Zustand
로 server, client 상태들을 관리하는 방법을 정리해 놓겠습니다.
예시로 movie 관련 api에서 데이터를 받아와 관리하는 과정입니다.
api/
├── movie/
| ├── movie-request.ts
| └── movie-request.type.ts
├── genre/
| ├── genre-request.ts
...
movie-request.ts
import axios from '@api/axios'; // axios interceptor
const movieRequest = {
fetchMovieDetails: async (movieId: number) => {
try {
const { data } = await axios.get(`movie/${movieId}?language=ko`);
return data;
} catch (error) {
return error;
}
},
...
} as const;
export default movieRequest;
아래와 같이 React Query의 useQuery
훅을 사용하여 커스텀 훅을 정의 후 사용합니다.
쿼리 키는 바뀔 수 있으므로 유지보수를 위해 QUERY_KEY
상수로 관리하였습니다.
import movieRequest from '@api/movie/movie-request';
...
import { useQuery } from '@tanstack/react-query';
export const useMovieDetailsQuery = (movieId: number) => {
const query = useQuery<TMovieDetailsFetchRes, Error>({
queryKey: [QUERY_KEY.movieDetails, movieId],
queryFn: async () => await movieRequest.fetchMovieDetails(movieId),
});
return query;
};
사용 예시
const { data: movieDetailsData, isLoading, isError } = useMovieDetailsQuery(movieId);
예시로 선택된 지역(region) 데이터를 관리하는 과정입니다.
stores/
├── region/
| ├── index.ts
| └── select-region-slice.ts
...
index.ts
지역 정보를 저장 및 없데이트(set)하는 store를 생성합니다.
import { persist } from 'zustand/middleware';
import { create } from 'zustand';
import { RegionState, selectRegionSlice } from './select-region-slice';
type SliceCreator = RegionState;
export const useRegionStore = create<SliceCreator>()(
persist(
(...set) => ({
...selectRegionSlice(...set),
}),
{
name: 'region-storage',
},
),
);
select-region-slice.ts
슬라이스 패턴을 사용하여 상태를 독립적인 슬라이스로 분리하였습니다. 이를 통해 코드의 가독성을 높일 수 있고, 상태 변경 로직을 독립적으로 유지할 수 있습니다.
import { StateCreator } from 'zustand';
export interface RegionState {
region: string;
setRegion: (name: string) => void;
initGroupId: () => void;
}
export const selectRegionSlice: StateCreator<RegionState> = (set) => ({
region: 'KR', // 초기 상태
setRegion: (region: string) => set({ region }), // 지역 설정 set함수
initGroupId: () => set(() => ({ region: 'KR' })), // 지역 초기화 함수
});
사용 예시
const { region, setRegion } = useRegionStore((state) => ({
region: state.region,
setRegion: state.setRegion,
}));