지난 포스팅에서도 이야기 했듯이 아띠즈 프로젝트를 진행하면서 사용된 API의 개수는 60개 이상이었기 때문에, 서버 데이터 관리가 필수적이었다. 많은 사용자들이 사용한다는 것을 가정하고, 데이터 캐싱 또한 필수적이었는데, React-query를 도입하면서 보다 간편하게 위에서 언급했던 사항들을 처리할 수 있었다. React-query에서 제공하는 useQuery, useMutation 등을 사용하는 것 또한 간편하지만, 여러 컴포넌트에서 데이터가 필요한 경우도 많았기에 재사용성을 고려하여 custom hook을 만들어 관리했다.
추가적으로 React-query에서 제공하는 제네릭을 사용하여 관리하는 데이터의 타입 또한 같이 다뤄보자.
useQuery와 useMutation 훅에서 사용되는 제네릭 타입은 다음을 참고했다.
useQuery 타입
export function useQuery<
TQueryFnData = unknown,
TError = unknown,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey
>
TQueryFnData : useQuery로 넘겨주는 쿼리 함수의 데이터 리턴 타입
TError : 쿼리 함수로 부터 예상되는 에러의 타입
TData : select 옵션을 사용했을 때 2차 가공된 데이터의 리턴 타입 (useQuery의 select 옵션은 따로 빼서 포스팅 하도록 하겠다.)
TQueryKey : useQuery로 넘겨주는 쿼리 키의 타입
useMutation 타입
export function useMutaion<
TData = unknown,
TError = unknown,
TVariables = void,
TContext = unknown
>
TData : useMutation에 전달한 뮤테이션 함수의 실행 결과 타입
TError : 뮤테이션 함수의 에러 타입
TVariables : 뮤테이션 함수에 전달할 인자의 타입
TContext : 뮤테이션 함수를 실행하기 전에 수행하는 onMutate 콜백 함수의 리턴 타입
useQuery를 사용한 custom hook
// @types/index.d.ts
interface Error {
code: string;
detail: string;
error: string;
status: number;
}
// @types/search.d.ts
interface RecentSearch {
id: number;
word: string;
}
아띠즈 프로젝트를 진행하면서 프로젝트에서 사용되는 타입들은 @types 폴더 내부에서 d.ts 파일을 통해 관리했다.
import instance from '@apis/_axios/instance';
export class ArtworkApi {
...
async getRecentSearch(): Promise<RecentSearch[]> {
const { data } = await instance.get('/search');
return data;
}
...
}
const artworkApi = new ArtworkApi();
export default artworkApi;
useQuery에 쿼리 함수로 넣어 줄 비동기 함수의 Promise 리턴타입을 작성하고, 아래와 같이 쿼리함수로 사용하도록 구현했다.
import artworkApi from '@apis/artwork/artworkApi';
import { useQuery } from 'react-query';
export const useGetRecentSearch = () => {
return useQuery<RecentSearch[], Error>('useGetRecentSearch', () =>
artworkApi.getRecentSearch(),
);
};
위의 코드는 최근 검색어를 가져오는 API를 useQuery를 사용하여 custom hook을 만든 것이다. useQuery 제네릭 타입으로 넘겨준 것으로 알 수 있듯이 리턴 데이터의 타입이 RecentSearch[]임을 추론할 수 있고, 에러의 타입 또한 @types 폴더 내의 index.d.ts 파일에서 작성한 Error 타입임을 예상할 수 있다.
useQuery custom hook 사용
import { useGetRecentSearch } from '@hooks/queries/useGetSearchArtWork';
export default function Search() {
const { data: RecentWords } = useGetRecentSearch();
...
return (
...
{RecentWords?.map((word: RecentSearch, idx) => (
<RecentSearchBox data={word}/>
))}
...
)
}
custom hook은 위와 같이 사용할 수 있다. useMutation을 활용한 custom hook을 사용하는 방법 또한 크게 다르지 않다.
오늘 포스팅에서는 useQuery custom hook의 사용방법을 useMutation custom hook 사용방법 보다 자세하게 다뤄보았지만, useMutation에는 onMutate, onSuccess, onError, onSettled 등 다양한 옵션이 존재하고, 해당 옵션들을 사용하여 구현한 기능들이 몇가지 더 소개할 것이 있기때문에 추가적인 포스팅을 통해서 더 자세하게 알아보도록 하겠다.
'개발' 카테고리의 다른 글
[개발] 카카오 로그인 구현하기 (0) | 2023.03.27 |
---|---|
Yarn-berry + NextJS(typescript) 보일러플레이트 만들기 (0) | 2023.03.05 |
[개발] React-query를 활용한 낙관적 업데이트 (0) | 2023.02.28 |
[개발] React-query를 활용한 데이터 필터링 (0) | 2023.02.25 |
[개발] Axios 모듈화 (instance 생성 및 interceptor의 사용) (0) | 2023.02.20 |