📚 1. 사전 지식
참고 링크 : React Query, Custom Hook, React-query에 Typescript 적용하기
React Query란?
React Query는 서버의 값을 클라이언트에 가져오거나, 캐싱, 값 업데이트, 에러핸들링 등 비동기 과정을 더욱 편하게 하는 데 사용된다.
React Query의 장점으로는, 아래의 구현하기 귀찮은 일들을 대신 수행한다.
- 캐싱
- get을 한 데이터에 대해 update를 하면 자동으로 get을 다시 수행한다. (예를 들면 게시판의 글을 가져왔을 때 게시판의 글을 생성하면 게시판 글을 get 하는 api를 자동으로 실행 )
- 데이터가 오래 되었다고 판단되면 다시 get (invalidateQueries)
- 동일 데이터 여러번 요청하면 한 번만 요청한다. (옵션에 따라 중복 호출 허용 시간 조절 가능)
- 무한 스크롤 (Infinite Queries (opens new window))
- 비동기 과정을 선언적으로 관리할 수 있다.
- react hook과 사용하는 구조가 비슷하다.
Custom Hook이란?
재사용 가능한 로직을 캡슐화하고 함수 컴포넌트에서 상태 관리나 사이드 이펙트를 수행하는 방법이다. Custom hook은 React의 Hooks API를 기반으로 하며, 함수의 이름은 'use'로 시작하면서, 일반 함수와 구별된다.
useQuery의 Types
export declare function useQuery<
TQueryFnData = unknown,
TError = unknown,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey
>(queryKey: TQueryKey, queryFn: QueryFunction<TQueryFnData, TQueryKey>, options?: Omit<UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>, 'queryKey' | 'queryFn'>): UseQueryResult<TData, TError>;
- TQueryFnData: queryFn의 return 값을 정하는 generic type
- TError: queryFn의 Error형식을 정하는 generic type
- Tdata: useQuery의 select option으로 queryFn의 데이터를 추가적으로 가공할 시 data에 담길 generic type, default는 TQueryKey를 그대로 따라갑니다.
- TQueryKey : queryKey 에 대한 generic type 명시하고 싶을 때 사용합니다.
참고로 queryKey 의 default type은 다음과 같습니다.
export declare type QueryKey = string | readonly unknown[];
useMutation의 Types
export declare function useMutation<
TData = unknown,
TError = unknown,
TVariables = void,
TContext = unknown
>(mutationKey: MutationKey, mutationFn?: MutationFunction<TData, TVariables>, options?: Omit<UseMutationOptions<TData, TError, TVariables, TContext>, 'mutationKey' | 'mutationFn'>): UseMutationResult<TData, TError, TVariables, TContext>;
- TData: mutation 비동기 함수 실행결과 generic type, onSuccess와 data에서 사용할 수 있습니다.
- TError : 마찬가지로 queryFn의 Error형식을 정합니다. onError, error에서 사용할 수 있습니다.
- Tvariables : mutate 함수에 전달할 인자를 지정하는 generic type입니다. mutate 함수에서 사용할 수 있습니다. 또한 각 callback 함수 (onSuccess, onError, onMutate, onSettled)에서 인자로 활용할 수 있습니다.
- TContext : mutation function을 실행하기 전에 수행하는 onMutate callback 함수의 return값에 대한 generic type입니다. onMutate의 결과 값을 onSuccess, onError, onSettled에서 활용하려면 해당 타입을 지정해서 활용할 수 있습니다.
🤩 2. 실제로 구현하기
1. Types 정의
// @types/chat.d.ts
interface ChatRoomById {
chatRoomId: number;
artist: {
id: number;
name: string;
responseTime: string;
};
member: {
id: number;
name: string;
responseTime: string;
};
messages: Message[];
}
// @types/index.d.ts
interface Error {
code: string;
detail: string;
error: string;
status: number;
}
- Error type의 경우 모든 api에서 공통적으로 사용하기 때문에 index.d.ts에 작성하였습니다.
2. Api에서 Type 적용
// apis/chat/chatApi.ts
async getChatRoom(id: number): Promise<ChatRoomById> {
const { data } = await instance.get(`/chat-rooms/${id}`);
return data;
}
- getChatRoom의 반환값으로 Promise <ChatRoomById>를 설정합니다.
3. useQuery에서 Type적용
// hooks/queries/chat/useGetChatRooms.ts
import { useQuery } from 'react-query';
import chatApi from '@apis/chat/chatApi';
const useGetChatRoom = (id: number) => {
return useQuery<ChatRoomById, Error>(
['useGetChatRoom', id],
() => chatApi.getChatRoom(id),
{
enabled: !!id,
},
);
};
export default useGetChatRoom;
- TData로 ChatRoomId Interface, TError로 Error를 설정하였습니다.
실제 코드는 다음과 같습니다.
index.ts : https://github.com/Att-ies/frontend/blob/dev/src/%40types/index.d.ts
useQuery : https://github.com/Att-ies/frontend/blob/dev/src/hooks/queries/chat/useGetChatRoom.ts
api : https://github.com/Att-ies/frontend/blob/dev/src/apis/chat/chatApi.ts
🤔 2. 느낀 점 / 배운 점 / 추가로 공부할 것
Typescript에는 정말 끝이 없다는 것을 알게되었다. 기존 React에도 적용할 Type들이 한가득인데, 새로 추가한 라이브러리에도 추가해야 할 Type 또한 한 가득이다. 그렇다면, 앞으로 Typescript는 얼마나 더 공부해야 하고, 어떻게 공부해야 할까?
참고 링크 : TS 공부법
Typescript는 초기 세팅이 되어 있는 Vite나 tsup을 추천한다.
1. 변수 선언과 함수 인자부터 적용하기
2. 타입 선언보다는 가급적 자동추론 사용하기
3. 백엔드 스키마 interface를 만드는 연습해보기 : 위 코드의 types파일처럼
5. 공식문서에 다 있지만, 양이 방대하다 보니 전부 다 할 수는 없음 => 빠르게 훑어보고, AutoComplete + Type검사용 플러그인이라는 생각으로 그때그때 필요한 것들만 찾아서 살펴보는 방식으로 접근하기
앞으로 프로젝트를 진행할 때 Typescript를 매 번 놓치지 않고 그때그때 적용하며 손과 머리에 익히도록 해보자 !
'개발 일지 > 개발 일지' 카테고리의 다른 글
[개발 일지] React Native 도전기 (1) (0) | 2023.05.16 |
---|---|
[개발 일지] React성능 최적화 (2) : React Query의 캐싱 기능 (1) | 2023.05.05 |
[개발 일지] React성능 최적화 (1) : React.memo로 사용자 경험 개선하기 (0) | 2023.05.03 |
[개발 일지] Next.js에서 접근성 향상하기 (접근성 점수 84점 -> 97점 향상시킨 썰) (0) | 2023.04.27 |
[개발 일지] JWT + 소셜 로그인을 정복해보자 (React + Spring Boot, Kakao Login, Naver Login) (0) | 2023.04.11 |
[개발 일지] Intersection Observer API & react-query를 이용한 무한스크롤 구현 (0) | 2023.02.28 |
[개발 일지] Suspense를 이용하여 모든 api에 Loading 화면을 설정하자 (NextJS, Suspense) (0) | 2023.02.18 |
[개발 일지] Axios instance 설정 끝장내기 (Axios, instance, interceptors, JWT) (0) | 2023.02.11 |