본문 바로가기
TIL

tanstack Query v5

by 은지:) 2024. 7. 28.
728x90
반응형

 

 

기존 상태 라이브러리는 비동기 및 서버 상태 관리에 적합하지 않다

우리는 서버 상태를 관리하기 위한 가장 좋은 라이브러리다!!



구 리액트 쿼리
현 탠스택 쿼리

 

 

 

서버 상태 관리란?

 

클라이언트에서 제어하지 않은 상태에서 관리됨

비동기 api 필요

사용자가 모르는 사이에 바뀔 수도 있음

 

 

캐싱

같은 데이터 요청 중복 제거

최대한 빠르게 업데이트 반영

 

 

 

stale-while-revaildate

 

http 캐싱에도 사용되는 캐싱 매커니즘

-> 캐싱된 데이터를 사용자에게 줌 + 비동기적으로 콘텐츠를 서버에서 revaildate

 

fetching

이건 fresh한 상태임

조건에 따라 (staleTime) stale로 바뀜

 

사용되지 않으면 inactive 로 바뀜

gcTime(cacheTime) 가비지 콜렉터 타임... 캐시를 제거하는 거임

 

 

QueryClient

모든 쿼리에 대한 상태/캐시를 가지고 있는 클래스임

QueryClient 인스턴스를 생성하여 쿼리 기능을 사용함

 

 

const queryClient = new QueryClient({
	defaultOption : {
    		queries : {
        		staleTime : 1000 * 60,
            		retry: 1
        	},
        	mutations : {
        		retry: 1
        	}
    	}
})

<QueryClientProvier client={queryClient}>
.............

 

 

서버에서 데이터를 받아올 때 사용하는 기능

v5라서 ({}) 객체 형체로 바뀜

const query = useQuery({
	queryKey: ["todo"],
    	queryFn : fetchTodo
})

 

 

 

enable : false , 쿼리 자동으로 실행여부

retry: 실패시 몇 번? 기본은 3번임

select : res에서 필요한 값만 추출

refetchInterval: 주기적으로 얼마나 부를 건지

throwOnError: error boundary로 에러를 전파할지 여부

data: resolved 된 데이터

 

 

 

 

 

 

 

 

 

 

 

 

isLoading : 최초 패치가 in-flight 상태 (캐시 있거나 없음) 

=> 처음 패칭했을 때 뜨는 거. 이후에 캐싱된 거 가져올 때는 작동 안 함

isFetching : fetch가 실행될 때마다 true (캐시 있음)

=> 캐싱 상관없이 모두 뜸

 

였는데

v5는 바뀌었다함

 

 

  • 처음 데이터를 가져올 때는 isLoading과 isPending이 모두 true
  • 캐싱된 데이터를 가져올 때는 isLoading만 true가 되고, isPending은 false 상태를 유지

 

둘이 바뀐듯...

 

 

 

useQueries

  const queries = useQueries([
    { queryKey: ['user'], queryFn: fetchUser },
    { queryKey: ['posts'], queryFn: fetchPosts },
  ]);
  
  
  const queries = useQueries({
    queries: [
      { queryKey: ['user'], queryFn: fetchUser },
      { queryKey: ['posts'], queryFn: fetchPosts },
    ],
  });
  
  
    const { data, isLoading } = useQuery(['user'], fetchUser, {
    placeholderData: {
      name: 'Loading...',
      age: null,
    },
  });
  
  placeholderData : 데이터 가져오기 전에 목데이터

 

useQuery를 여러개 부를 때

 

useQueries를 사용하면

 const queries = useQueries([
    { queryKey: ['user'], queryFn: fetchUser },
    { queryKey: ['posts'], queryFn: fetchPosts },
  ]);

  const userQuery = queries[0];
  const postsQuery = queries[1];

  if (userQuery.isLoading || postsQuery.isLoading) return <div>Loading...</div>;
  if (userQuery.error || postsQuery.error) return <div>Error: {userQuery.error?.message || postsQuery.error?.message}</div>;

 

이렇게 병렬적으로 가져오기도하면서

각각 error 처리가 가능함

 

 

  • 독립적인 상태 관리가 필요할 때: useQueries를 사용하는 것이 더 나음
  • 간단하게 여러 데이터를 한 번에 가져올 때: Promise.all을 사용하여 한 쿼리 내에서 처리

 

 

 

Mutations

URD 에 사용되는 기능 (CRUD)

 

const query = useMutation({
	queryFn: fetchTodo
})

 

 

onMutation : mutate 함수가 실행되기 전에 실행되는 함수

(optimistic update)

mutate : mutation 함수를 실행시키는 함수

onSettled : 실패했든 성공했든 상관없이 호출

 

queryClient.invalidateQueries({

........

})

 

이건 todo 만들어 놓고 다시 쿼리 키를 이용해 데이터를 부르려는 거임

업데이트 쳤으니까 새로운 거 받아와야 함

 

 

useInfiniteQuery

 

isFetchingNextPage가 page +1 인 듯

 

 

 

신박한 거....

 

캐싱된 데이터를 가져와서 다른 거 패칭하기 전에 미리 보여줄 수도 있음

 

 

 

낙관적 업데이트

 

 

1. variables

 

 

 

2. onMutate를 통한 낙관적 업데이트

  const mutation = useMutation(updateUser, {
    onMutate: async (newData) => {
      // 기존 쿼리 데이터 취소
      await queryClient.cancelQueries(['user']);

      // 스냅샷으로 이전 값 가져오기
      const previousUserData = queryClient.getQueryData(['user']);

      // 낙관적 업데이트 수행
      queryClient.setQueryData(['user'], (old) => ({
        ...old,
        ...newData,
      }));

      // 오류 발생 시 롤백을 위해 스냅샷 반환
      return { previousUserData };
    },
    onError: (err, newData, context) => {
      // 오류 발생 시 롤백
      queryClient.setQueryData(['user'], context.previousUserData);
    },
    onSettled: () => {
      // 변이 완료 후 데이터 다시 가져오기
      queryClient.invalidateQueries(['user']);
    },
  });

  const handleUpdate = () => {
    mutation.mutate({ name: 'New Name' });
  };

 

 

variables 와 onMutate 의 낙관적 업데이트 차이

 

 

variables은 예시와 같이 업데이트가 진행중인걸 알려주려고 만든 거임

onMutate의 낙관적 업데이트는 말 그대로 낙관적으로 판단하고 빠르게 UI를 보여주는 거임

 

이거 두개는 같이 못 쓸 거 같은데

왜 두개 다 함께 쓰라고 권장하는 건지 모르겠음

 

 

 

setQueryData

queryClient.setQueryData(queryKey, updater);
queryKey: 업데이트할 쿼리의 키.
updater: 새로운 데이터 또는 기존 데이터를 업데이트하는 함수.

 

캐시된 데이터 가져오면서 바꾸는 거임

위에 onMutate 처럼

 

 

 

useSuspenseQuery

 

데이터를 불러오는 동안 fallback UI를 대신 보여주는 기능

useQuery에 suspense: true 옵션 넣은 거랑 똑같음

const query = useSuspenseQuery({
	..........
})

 

suspense로 감싼 컴포넌트에서 useQuery suspense : true 설정 안하고 그냥 쓰면

suspense fallback 기능을 못 쓴다고 함....

글쿤

 

 

 

 

보통 폴더명 이렇게 짓는 듯

 

 

 

 

 

===============================

 

 

로딩 상태 관리

낙관적 업데이트

캐싱 기능

 

때문에 많이 썼던 듯

이제야 이해가 갔다

 

contextAPI를 사용하긴 했는데 (키를 이용해서 관리하니까 필요했던 듯, 캐싱도 그렇고)

 

서버 상태(fetch 데이터) // 클라이언트 상태 를 분리해서 봐야하는 듯

단순 서버 상태를 위한 라이브러리였음

 

 

 

 

참고

https://www.youtube.com/shorts/-RsCv5uZziI

https://www.youtube.com/watch?v=3e-higRXoaM

https://www.youtube.com/watch?v=n-ddI9Lt7Xs

728x90
반응형

댓글