사용하고 있던 기존의 useApi훅 소개
문제점 : 너무 많은 Api요청을 해야 한다는 것.
- 이전 useApi를 사용했던 프로젝트와 다른 점
- 이번 프로젝트 특징
계획 및 실제 구현 해보기
사용하고 있던 기존의 useApi훅
import { useEffect, useState, useCallback } from 'react';
import { API_FETCHER, ApiMethods } from '@utils/axiosConfig';
import { useErrorBoundary } from 'react-error-boundary';
import { AxiosError, AxiosResponse } from 'axios';
import axios from 'axios';
interface UseApiParams {
method?: ApiMethods;
path?: string;
data?: any;
shouldInitFetch?: boolean;
initialResult?: string;
}
interface TriggerPropsType
extends Omit<UseApiParams, 'shouldInitFetch' | 'initialResult'> {
applyResult?: boolean;
isShowBoundary?: boolean;
}
type TriggerType = ({
...props
}: TriggerPropsType) => Promise<AxiosResponse<any, any>>;
const useApi = ({
method = 'get',
path = '',
data = {},
shouldInitFetch = false,
initialResult = '',
}: UseApiParams) => {
const [result, setResult] = useState(initialResult);
const [loading, setLoading] = useState(false);
const [reqIdentifier, setReqIdentifier] = useState('');
const [error, setError] = useState({});
const { showBoundary } = useErrorBoundary();
const trigger: TriggerType = useCallback(
async ({
method: triggerMethod = method,
path: triggerPath = path,
data: triggerData = data,
applyResult = true,
isShowBoundary = true,
}) => {
setLoading(true);
setReqIdentifier(triggerMethod + 'Data');
try {
const triggerResult = await API_FETCHER[triggerMethod as ApiMethods](
triggerPath,
triggerData
);
if (applyResult) {
console.log('result를 apply합니다');
setResult(triggerResult);
return;
}
return triggerResult;
} catch (err) {
console.log(err);
if (axios.isAxiosError(err) && isShowBoundary) {
//에러 바운더리를 보여줘야 할때만 보여줌
showBoundary(err);
return;
}
axios.isAxiosError(err) && setError(err);
return;
} finally {
setLoading(false);
}
},
[data, method, showBoundary, path, result]
);
useEffect(() => {
shouldInitFetch && console.log('초기 요청합니다!!', method, path);
shouldInitFetch && trigger({ method, path, data });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return { result, loading, reqIdentifier, trigger, error };
};
export default useApi;
이 자체만으로도 다양한 기능을 넣었다고 생각했지만,
이번 프로젝트를 시작하면서 약간 수정해야 할 필요성을 느꼈다.
문제점 : 너무 많은 Api요청을 해야 한다는 것.
- 이전 useApi를 사용했던 프로젝트와 다른 점
장바구니에서 수량이나 체크여부를 저장하는 단순한 정보였기 때문에
useDebouncing으로 가장 나중에 요청한 것만
실제 api요청을 보내게 만들어도 되었었다.
(이건 왜 api요청을 해야하냐는 이유는 여기에 있다
https://wha-haha.tistory.com/222)

- 이번 프로젝트 특징
그러나 이번에는 사용자가 일별로 클릭하는데, 주차별 캘린더가 있어서
해당 일자를 클릭할 때마다 계속 api 요청을 받아와야 했다.

그렇다면 useApi를 수정해서 caching 기능을 넣어보자!
계획 및 실제 구현 해보기
react-query를 활용하여
useApi에 메서드별로
get은 useQuery에서 return하는 값을,
나머지 메서드는 useMutation에서 return하는 값을 받아와서
기존의 단순한 사용성은 유지하고
캐싱기능만 추가하도록 한다.
1. react query설치
2. useMutationggu.ts 파일 작성
3. useQueryggu.ts 파일 작성
4. useApi를 변형한 useCachingApi파일 작성
1. react-query설치
- 설치
npm i react-query
- QueryClientProvider 제공
root.render(
<ErrorBoundary fallback={<Error />}>
<QueryClientProvider client={queryClient}>
<ToastProvider>
<BrowserRouter>
<Provider store={store}>
<App />
</Provider>
</BrowserRouter>
</ToastProvider>
</QueryClientProvider>
</ErrorBoundary>
);
- QueryClient 설정
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 20000
}
}
});
staleTime을 얼마나 할지는 다시 고려 해보자
retry: 1,
retryDelay: 0,
onError,
위의 세 옵션도 생각해보기
retry : 실패한 쿼리 자동으로 재시도 횟수
retryDelay:몇분 후 재시도 할지
[트러블슈팅] react-query useMutation onSuccess 안 되는줄 알았던 바보 여기있어요!
라이브러리를 알고 쓰자 / 코드는 거짓말하지 않는다
velog.io
useApi의 매개변수
1. method: method값에 따라 useMutation vs useQuery사용 여부
2. path: 요청시에 전달
3. data: useMutation 요청시에 전달
4. shouldInitFetch: useEffect로 기존의 코드 활용 ㅇ
5. InitialResult: 넣어준 이유는 초깃값이 undefined일때 화면을 렌더링 함으로써 에러가 났기 때문.
기존과 동일하게 result를 return 해줄 때 initialValue를 기본값으로 넣어주면 될듯 ....?
useMutation
필요성:
캐싱기능이 들어가게 되면 무조건 캐싱이 되어버리므로,
데이터가 변경되었을때 수정 작업을 해야함.
api요청은 무조건 useCachingApi를 사용하므로
method에따라 useMutation이냐 useQuery냐는것은 useCachingApi에서 분기해주어야 함.
ex:
기록 조회할때는 useQuery로 캐싱된 값을 가져오고
기록을 수정, 삭제, 생성할 때 새로운 값을 캐싱해야함.
const { data, isLoading, mutate, mutateAsync } = useMutation(mutationFn, options);
useMutationggu 훅
itemId를 받아서 useMutation을 return해줌
options 고려해야할것
1. onMutate : mutation이 실행되기 전 먼저 실행
=> (요청시 바로 UI에 반영하기 위해 기존 query를 가져오고 즉시 업데이트)
2. onSuccess : mutation이 성공하면 실행 (staleTime을 지정해야 성공시 InvalidateQueries 요청이 유효해질 수 있음)
=> InvalidateQueries요청! (itemId값으로)
3. onError : mutation 과정에서 에러가 발생되면 실행
=> 에러문구 띄워주고 확인시 다시 요청...
4. onSettled: 성공/에러에따라 해당 데이터 전달 받음
return값
data:
mutate: mutate 를 호출해서 mutation 을 실행시킬 수 있다.
variables 는 mutationFn 에 전달하는 객체이다.
onSuccess, onSettled, onError 는 useMutation option에 설명한 것과 동일하다
isLoading,
mutate,
mutateAsync
InvalidateQueries : 상태에 대한 정보가 변경되었을 때 캐싱된 데이터 변경
react-query 사용시 invalidateQueries를 이용해 캐싱 값 refetch하기
invalidateQueries로 데이터 업데이트하기
velog.io
'프로젝트' 카테고리의 다른 글
타입 전역객체로 사용할때 협업시 문제점 (0) | 2024.02.01 |
---|---|
useApi훅에 react-query활용하여 caching기능 넣어보기 (2) - useMutation만으로 useApi 훅 구현 해보기 (0) | 2024.01.25 |
compound component형태 (0) | 2024.01.07 |
dependencies와 devDependencies의 구분 (0) | 2024.01.04 |
[문제] dispatch후 navigate해야 하는데 먼저 되는 현상: thunk시도 (2) | 2023.12.26 |