일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- http
- W
- data
- nosql
- this
- url
- jQuery
- db
- useEffect
- firestoredatabase
- SQL
- TMDB
- CSS
- web
- github
- 배포
- Database
- supabase
- HTML
- REACT
- API
- Fetch
- Cloud
- Boostrap
- IntersectionObserver
- Github Pages
- til
- bootstrap
- Protocol
- JavaScript
- Today
- Total
072DATA
TanStack Query 정리 ( useQuery, useMutation ) 본문
tanStack Query? => 강력한 비동기나 서버 상태를 관리하게 해주는 도구
서버상태 -> 직접 서버에 저장되고 관리되는 데이터
서버 상태의 특징
- 데이터를 fetching하거나 update할 때 비동기 api 요청이 필요
- 나 혼자만 사용하는게 아니기 때문에 다른 사람이 변경이 가능
- 가져온 데이터가 최신 상태로 유지하기 어려울 수 있음
서버 상태를 관리하는데 어려움을 느끼는 점에서
캐싱, 데이터에 대한 중복 요청 해결, 오래된 데이터 업뎃,
데이터 지연 로드 성능 최적화 등등등
이러한 과정을 tanStack Query로 관리가 가능!!!!!
TanStack Query 설치 명령어
npm install @tanstack/react-query
yarn add @tanstack/react-query
기본 설정
//main.jsx
import { createRoot } from "react-dom/client";
import App from "./App.jsx";
import "./index.css";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient();
createRoot(document.getElementById("root")).render(
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
QueryClient =>
캐시와 상호작용이 가능해짐 ( defaultOptions로 query나 mutation에 옵션 추가 가능)
또 다양한 메서드가 존재 ( useQuery, useMutaion, invalidateQuries 등)
QueryClientProvider =>
QueryClient를 애플리케이션에 연결하여 최상단에 QueryClientProvider를 감싸서
하위 컴포넌트에게 기능을 제공
TanStack Query에서 서버의 데이터 상태 ->
fresh -> 쿼리 인스턴스가 새롭게 Mount 된 상태 즉 최신 데이터
stale -> fresh의 반대 오래된 데이터
서버의 데이터 상태에 따른 TanStack Query의 특징
- fresh 상태일 때는 서버에서 데이터를 다시 가져올 필요가 없다고 간주
- 기본적으로 쿼리 데이터가 새로 가져온 직후에는 fresh 상태가 됨
- stale 상태일 때는 데이터를 다시 가져와야 할 필요가 있다고 간주
- Tanstack Query는 기본적으로 데이터를 가져온 후 일정 시간이 지나면 그 데이터를 stale로 간주함.
이는 staleTime 옵션을 사용해 설정할 수 있음
useQuery =>
Query Key를 기반으로 Query Caching을 진행
서버로부터 데이터를 갖고오기 위하여 Promise 기반의 메서드 사용 가능 (get 요청)
ex)
export const useGetPlaces = () => {
return useQuery({
queryKey: ["posts"],
queryFn: bookmarkApi.fetchPlaces //bookmarkApi.fetchPlaces => API호출을 하는 함수,
});
};
options =>
queryKey : 배열로 지정해야하고 단일 문자열이나 중첩 객체 등 복잡한 형태 가능
queryFn : Promise를 반환하는 함수 ( get 요청 )
staleTime : fresh에서 stale 상태로 변경되는데 걸리는 시간 설정
const { data, isLoading, isError } = useGetPlaces();
return =>
data: Promise 에서 resolved된 데이터
error: 오류 객체
isLoading: 캐싱된 데이터가 없을 때 로딩 여부에 따라 true/false반환
isPending: 캐싱된 데이터 없고 쿼리 시도가 아직 완료되지 않은 상태
isFetching: 캐싱된 데이터가 있더라도 쿼리가 실행되면 로딩 여부에 따라 true/false 반환
isPaused: 쿼리는 fetch를 원하지만 (갑자기?) 멈춘상태 => 네트워크가 끊어졌을 때 예외 처리시 유용
isSuccess: 요청 성공 상태
isError: 에러 발생 상태
useMutation =>
POST, PATCH, PUT, DELETE 요청 같은 서버에 사이드 이펙트를 일으킬 때 사용함 ( 게시물 추가, 수정, 삭제 등)
ex)
const { mutate } = useMutation({
mutationFn: bookmarkApi.handleBookmarkToggle,
onMutate: async (updateData) => {
await queryClient.cancelQueries({ queryKey: ["posts"] });
const previousPlaces = queryClient.getQueryData(["posts"]);
const placeToUpdate = previousPlaces.find((place) => place.id === updateData.id);
const updatedBookmarks = updateData.bookmarked
? placeToUpdate.bookmarks.filter((user) => user.userId !== updateData.userId)
: [...placeToUpdate.bookmarks, { userId: updateData.userId }];
queryClient.setQueryData(["posts"], (places) =>
places.map((place) => (place.id === updateData.id ? { ...place, bookmarks: updatedBookmarks } : place))
);
return { previousPlaces };
},
onError: (err, updateData, context) => {
queryClient.setQueryData(["posts"], context.previousPlaces);
},
onSettled: () => {
queryClient.invalidateQueries(["posts"]);
}
});
options =>
mutationFn: promise를 반환하는 함수 ( POST, PATCH, PUT, DELETE 요청 )
onMutate: mutationFn가 실행되기 전 먼저 실행 시킬 로직이 있을 때 사용 ( 낙관적 업데이트 등)
onSuccess: mutationFn 성공했을 때 실행
onError: mutationFn 실패했을 때 실행
onSettled: 모든 구문이 끝나고 마지막에 실행
const {
mutate,
data,
error,
isSuccess,
isPending,
isError,
isIdle,
} = useBookmarkUpdated();
return =>
data : mutation 함수가 리턴한 promise에서 resolved된 데이터
error: mutation 중 발생한 오류 객체
isSuccess: mutation이 성공하여 데이터를 이용할 수 있는 상태
isPending: mutation이 진행 중인 상태
isError: mutation 중 에러가 발생한 상태
isIdle: mutation 이 아직 실행되지 않았거나, 이전 되고 리셋된 상태
const { mutate } = useMutation({
mutationFn: bookmarkApi.handleBookmarkToggle,
onSuccess: () => {
queryClient.invalidateQueries(["posts"]);
},
Query invalidation =>
queryClient의 메서드이며 쿼리를 무효화한 뒤 최신화 함( stale => fresh )
useMutation을 사용할 때 서버 상태를 변경하고나서 캐시 자체에 패칭하는 기능이 없기 때문에
실제로 데이터는 변경되었지만 UI는 변경되지 않음 그렇기 때문에
invalidatedQueries를 사용해서 쿼리의 상태를 stale하고 fresh로 변경
invalidatedQueries에 queryKey가 없으면 캐시 안에 있는 모든 쿼리들이 무효화
queryKey가 존재하면 해당 쿼리키를 갖고 있는 쿼리를 무효화 시킴
마치며
TanStack Query를 활용하면서 직접 실감되는 부분은 클라이언트의 전역 상태를 관리하는 zustand나
Context API에서 API를 요청하는 함수가 많았는데 TanStack Query를 사용하니 아주 깔끔하게 코드가 정리 됐고
서버에서 받아온 데이터를 상태에 따라 리렌더링 해주는 것도 편하게 관리가 되는 것 같음
제공되는 메소드가 유용한게 굉장히 많은데 현재 프로젝트 진행중에 북마크 기능을 구현하면서
onMutation을 통해서 낙관적 업데이트를 구현하여 네트워크 상태가 좋지 않거나 속도가 느릴 때도
UX를 개선할 수 있었기 때문에 아주 좋은 라이브러리가 아닌가 생각이 든다 내일은 북마크 기능 설명회 해야겠음 ㅅㄱ
'Anything > 끄적끄적' 카테고리의 다른 글
면접 질문 대답해보기 ( 1주차 ) (2) | 2024.10.22 |
---|---|
최종 프로젝트 계획하기 ( MVP와 UT ) (2) | 2024.10.19 |
json-server 사용하기 (0) | 2024.09.10 |
`끄적끄적` 인증과 인가 간단한 개념 정리 ( 쿠키, 세션, 토큰, JWT ) (0) | 2024.09.09 |
`끄적끄적` .env 로 환경 변수 관리하기 (VITE) (0) | 2024.08.29 |