일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- react
- App Runner
- 유데미
- 자바스크립트
- cs #네트워크
- javascript
- 프로젝트캠프
- 해시
- #프로젝트캠프 #프로젝트캠프후기 #유데미 #스나이퍼팩토리 #웅진씽크빅 #인사이드아웃 #IT개발캠프 #개발자부트캠프 #리액트 #react #부트캠프 #리액트캠프
- IT개발캠프
- 인사이드아웃
- 알고리즘
- 개발자부트캠프
- 웅진씽크빅
- 스나이퍼팩토리
- React.js
- typescript
- react-query
- 스레드
- ip
- 타입스크립트
- 프로세스
- CS
- 네트워크
- html
- 메모리
- Algorithm
- BFS
- 프로그래머스
- 리액트
- Today
- Total
Bin's Blog
React-Query란?(2편) 본문
글의 시작
오늘 다루는 주제는 지난 시간에 이어서 React-Query에 대해서 계속 알아보자.
특별히, 대표적인 React-Query의 기능들에서 살펴보고자 한다.
🛠️ 대표적인 기능들
React-Query에서 data fetching을 위해 제공하는 대표적인 기능들을 살펴보자
기본적으로 GET에는 useQuery가, PUT, UPDATE, DELETE에는 useMutation이 사용된다.
useQuery
- 첫 번째 파라미터로 unique key를 포함한 배열이 들어간다. 이후 동일한 쿼리를 불러올 때 유용하게 사용된다.
- useQuery는 기본적으로 3개의 인자를 받는다. 첫 번째 인자가 queryKey(필수), 두 번째 인자가 queryFn(필수), 세 번째 인자가 options(optional)이다. (아래 예제에서 자세하게 설명하겠다)
- 두 번째 파라미터로 실제 호출하고자 하는 비동기 함수가 들어간다. 이때 함수는 Promise를 반환하는 형태여야 한다.
- 최종 반환 값은 API의 성공, 실패 여부, 반환값을 포함한 객체이다.
queryKey
const getSuperHero = async ({ queryKey }: any) => {
const heroId = queryKey[1]; // queryKey: ['super-hero', '3']
return await axios.get(`http://localhost:4000/superheroes/${heroId}`);
};
const useSuperHeroData = (heroId: string) => {
// 해당 쿼리는 heroId에 의존
return useQuery(["super-hero", heroId], getSuperHero);
};
queryKey는 v4부터 무조건 배열로 지정해야 한다.
useQuery는 첫 번째 인자인 queryKey를 기반으로 데이터 캐싱을 관리한다.
만약, 쿼리가 특정 변수에 의존한다면 배열에다 이어서 넣어주면 된다. ex: ["super-hero", heroId, ...]
이거 매우 중요하다. 예를 들어, queryClient.setQueryData(캐시 데이터 즉시 업데이트 할 때 사용) 등과 같이 특정 쿼리에 필요 할때 초기에 설정해둔 포맷을 지켜줘야 제대로 쿼리에 접근 할 수 있다. (필자는 이 사실을 모르고 했다가 고생했었다...)
queryFn
const getSuperHero = async (heroId: string) => {
return await axios.get(`http://localhost:4000/superheroes/${heroId}`);
};
const useSuperHeroData = (heroId: string) => {
return useQuery(["super-hero", heroId], () => getSuperHero(heroId));
};
useQuery의 두 번째 인자인 queryFn는 Promise를 반환하는 함수를 넣어야한다.
참고로, queryKey 예제와 queryFn 예제가 약간 차이점이 존재한다.
queryKey 예제는 2번째 queryFn로 getSuperHero 함수를 바로 넘겨주고, getSuperHero에서 매개 변수로 객체를 받아와 해당 객체의 queryKey를 활용하고 있다.
queryFn 예제는 그냥 2번째 queryFn에 화살표 함수를 사용하고, getSuperHero의 인자로 heroId를 넘겨주고 있다.
해당 두 가지 방법의 결과는 동일하다.
options
const useSuperHeroData = (heroId: string) => {
return useQuery(["super-hero", heroId], () => getSuperHero(heroId), {
cacheTime: 5 * 60 * 1000, // 5분
staleTime: 1 * 60 * 1000, // 1분
// ...options
});
};
여기에는 1편에서 살펴봤듯이 cacheTime, staleTime 등 다양한 옵션을 추가해서 캐싱 데이터를 관리할 수 있다.
자세한 것은 공식문서를 참고하자.
사용 예시
// 기본 설정
import {
QueryClient,
QueryClientProvider,
useQuery,
} from '@tanstack/react-query'
const queryClient = new QueryClient()
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
)
}
function Example() {
const { status, isLoading, isError, error, data, isFetching, ... } = useQuery({
// 고유키
queryKey: ['repoData'],
queryFn: () =>
fetch("api").then(
(res) => res.json(),
),
})
// 로딩중일때
if (isLoading) return 'Loading...'
// 만약에 에러가 난다면
if (error) return 'An error has occurred: ' + error.message
return (
<div>
<h1>{data.name}</h1>
<p>{data.age}</p>
</div>
)
}
useQuery 함수가 반환하는 객체를 보면 isLoading을 통해 로딩 여부를, error를 통해 에러 발생 여부를, data를 통해 성공 시 데이터를 반환할 수 있다.
isLoading과 error를 이용하여 각 상황 별 분기를 쉽게 진행할 수 있다.
useQueries
여러 개의 useQuery를 한 번에 실행하고자 하는 경우, 기존의 Promise.all()처럼 묶어서 실행할 수 있도록 도와준다.
// 두 query에 대한 반환값이 배열로 묶여 반환된다
const results = useQueries({
queries: [
{ queryKey: ['post', 1], queryFn: fetchPost, staleTime: Infinity},
{ queryKey: ['post', 2], queryFn: fetchPost, staleTime: Infinity}
]
})
useMutation
서버의 data를 post, patch, put, delete와 같이 수정하고자 한다면 useMutation을 이용한다.
const CreateTodo = () => {
const mutation = useMutation(createTodo, {
onMutate() {
/* ... */
},
onSuccess(data) {
console.log(data);
},
onError(err) {
console.log(err);
},
onSettled() {
/* ... */
},
});
const onCreateTodo = (e) => {
e.preventDefault();
mutation.mutate({ title });
};
return <>...</>;
};
- useMutation의 반환 값인 mutation 객체의 mutate 메서드를 이용해서 요청 함수를 호출할 수 있다.
- mutate는 onSuccess, onError 메서드를 통해 성공 했을 시, 실패 했을 시 response 데이터를 핸들링할 수 있다.
- onMutate는 mutation 함수가 실행되기 전에 실행되고, mutation 함수가 받을 동일한 변수가 전달된다.
- onSettled는 try catch finally 구문의 finally처럼 요청이 성공하든 에러가 발생되는 상관없이 마지막에 실행된다.
글의 마무리
이 글을 작성하면서 공식 문서를 많이 참고했는데, 내가 생각했던 것보다 더 많고 풍성한 내용이 가득하다.
cacheTime, staleTime, uesQueries은 실제로 적용해 보지 못했던 부분들이어서 아쉽다.
useMutation에서도 내가 onSuccess() 메서드를 제외하고는 다른 메서드는 사용 안 해봤다.
그래서 최근 진행한 프로젝트를 리팩토링하면서 오늘 배웠던 내용을 실제로 적용해서 내 것으로 만들겠다.
'React.js' 카테고리의 다른 글
오늘의 React(React란? - 1편) (0) | 2023.10.12 |
---|---|
Class component vs Functional component (0) | 2023.10.03 |
React-Query란?(1편) (0) | 2023.09.11 |
Flux 패턴 (0) | 2023.09.01 |
[React.js] 오늘의 디버깅 (0) | 2023.08.01 |