AndChill 개발일지(3) - 우아하게 상태관리 하기

dali·2024년 8월 2일
0

And Chill 개발 기록

목록 보기
3/9
post-thumbnail

본격적으로 코드를 뚝딱이기 전에 프로젝트에서 React Query Zustand 로 server, client 상태들을 관리하는 방법을 정리해 놓겠습니다.

React Query로 server state 관리


예시로 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);

Zustand로 client state 관리


예시로 선택된 지역(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,
}));

0개의 댓글

관련 채용 정보