React Query 시작하기

이재철·2023년 2월 26일
0

react-query

목록 보기
1/12
post-thumbnail

QueryClientProvider

  • QueryClientProvider 컴포넌트로 감싸주고 QueryClient 값을 Props로 주입합니다.
  • 앱 전체에 사용하고자하면 최상위 컴포넌트를 감싸줍니다.
import React from 'react';
import './App.css';
import { QueryClientProvider, QueryClient } from '@tanstack/react-query';

const queryClient = new QueryClient();

const App = () => {
  return (
    <QueryClientProvider client={queryClient}>
      <div className="App"></div>
    </QueryClientProvider>
  );
};

export default App;

QueryClient Default Options 적용하기

  • QueryClient에서 모든 query 또는 mutation 기본 옵션을 추가할 수 있습니다.

QueryClient 의 Default Option 적용

QueryClient의 Default Option

import React from 'react';
import './App.css';
import { QueryClientProvider, QueryClient } from '@tanstack/react-query';

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      retry: 0,
      suspense: true,
      useErrorBoundary: true
    },
    mutations: {
      retry: 0,
      suspense: true,
      useErrorBoundary: true
    }
  },
})

const App = () => {
  return (
    <QueryClientProvider client={queryClient}>
      <div className="App"></div>
    </QueryClientProvider>
  );
};

export default App;

setQueryDefaults 사용

  • useQuery에서 직접 옵션을 설정하지 않고, 가능한 기본값을 사용하며 재정의 및 특정 쿼리에 대한 변경이 필요한 경우 queryClient.setQueryDefaults 사용
...
// ✅ only todos will retry 2 times
queryClient.setQueryDefaults('getUser', { retry: 2 })
...

useQuery 적용

  • 특정 도메인 페이지에서 필요한 옵션들을 구체적으로 설정
const {data: user, error, status} = useQuery(
  ['getUser'],
  getUserApi,
  {
  	enabled: !!userId,   
    onError: () => {...},
    onSuccess: () => {...}
  }

브라우저에서 사용자가 최신 데이터를 바라봐야 되는 경우

  • 사용자가 해당 화면을 보고 있는 경우
  • 페이지 전환 시
  • 페이지 전환 없이 새로운 데이터 요청 시
refetchOnWindowFocus, // default: true
refetchOnMount, // default: true
refetchOnReconnect, // default: true
  
staleTime // default: 0
cacheTime, // default: 5분 (60*5*1000)

다음과 같은 경우 데이터를 Refetching 자동으로 다시 가져옴

  • refetchOnMount: 쿼리의 새 인스턴스가 마운트 된 경우
  • refetchOnWindowFocus: window가 다시 포커스가 된 경우
  • refetchOnReconnect: 네트워크가 끊어졌다가 다시 연결 된 경우
  • refetchInterval: 쿼리의 refetch interval이 설정된 경우
  • 기본적으로 쿼리 결과는 데이터가 실제로 변경되는지 감지하기 위해 공유함
  • 변경되지 않는 경우 데이터 참조가 변경되지 않는 상태 유지

Default Option

enable

  • useQuery를 동기적으로 사용 가능
  • false로 설정하면 쿼리가 자동으로 호출되지 않음 ➡ 최초 선언 시 호출을 막을수 있음
  • default: true
const {data: user, error, status} = useQuery(
  ['getUser'],
  getUserApi,
  {
  	enabled: !!userId // true가 되면 getUserApi를 실행함
  }

staleTime

  • 쿼리 데이터가 fresh에서 stale로 전환되는데 걸리는 시간
  • Infinity로 설정하면 쿼리 데이터는 직접 캐시를 무효화할 때 까지 fresh상태로 유지
  • 캐시는 메모리에서 관리 ➡ 브라우저 새로고침 후 다시 가져옴
  • default: 0

refetchInterval

  • 일정한 간격으로 refetching이 가능
  • 밀리초로 계속 refetching
  • default: false

refetchIntervalInBackground

  • 탭/창 백그라운드에 있는 동안 쿼리 refetching
  • default: false

refetchOnWindowFocus

  • 윈도우 다시 포커스되었을 때, 데이터 호출 여부
  • default: false

refetchOnReconnect

  • 네트워크가 끊어졌다가 다시 연결된 경우 데이터 호출 여부
  • default: true

refetchOnMount

  • mount 된 경우 reftch 여부 결정합니다.
  • true로 설정한 경우 stale 상태일 때 refetch
  • default: true
  1. parent component render
  2. useQuery 호출 ➡ isFetching, isLoading : true
  3. 요청완료
    • isFetching, isLoading : false
    • query key 값을 식별자 데이터 캐싱처리
    • data fresh상태, staleTime 이후 stale 상태 변환
  4. parent component 리 랜더링되며 자식 children component의 useQuery 호출
    • 데이터 stale상태, refetchOnMount:true 이므로 background refetch가 실행

➡ 처음 fetching 이후 staleTimerefetchOnMount 설정으로 refetching을 하며 총 2번 요청

retryOnMount

  • false로 설정한 경우 쿼리에 오류가 포함되어 mount 시, 쿼리 재시도되지 않습니다.

notifyOnChangeProps

  • 속성이 변경되는 경우만 다시 렌더링 옵션
const {data: user, error, status} = useQuery(
  ['getUser'],
  getUserApi,
  {
  	notifyOnChangeProps: ['data'],
  }
  • const {data: user, error, status} = useQuery(...);data만 변경이 된 경우 리렌더링
    🚫 status를 이용하여 조건부 렌더링을 하는 경우 문제가 발생함 ➡ status 의 변경여부를 감지할 수 없음

tracked

  • 리액트 쿼리는 렌더 중에 사용 중인 속성을 알아서 추적하며, 사용 중인 속성들의 변화가 있는 경우 리렌더링을 함
notifyOnChangeProps: 'tracked'
default 설정이 아닌 경우
  • object rest destructuring을 사용한다면 모든 필드를 추적함으로 주의해야 함🤦
  • 의존성 배열에 사용 중인 속성을 주입하지 않는 다면 정확한 추적이 되지 않음
const userData = useQuery(...);
React.useEffect(() => {
    console.log(userData.data)
})

🚫 tracked를 설정하여 사용 중인 속성은 약간의 오버헤드가 발생할 수 있으므로 상황에 따라 사용해야 함


onSuccess

  • queryFunction 성공적으로 데이터를 가저온 경우 호출되는 함수
  • 쿼리가 성공적으로 새로운 데이터를 가져오거나 setQueryData를 통해 캐시가 업데이트가 될 때마다 실행합니다.

onError

  • queryFunction에서 오류가 발생한 경우 호출되는 함수
  • 쿼리에 오류가 발생하고 오류가 전달되면 콜백 실행

onSettled

  • queryFunction의 성공, 실패 여부와 관계없이 모두 실행되는 함수

useErrorBoundary

  • suspense: true 또는 useErrorBoundary: true 설정한 경우, 모든 오류는 에러바운더리로 넘겨짐
  • default: false

select

  • 쿼리 함수에 반환된 데이터의 일부를 변환하거나 선택
{
 	 select: data => data.filter((user) => user.id === 1));
}

suspense

  • true 설정하면 status === 'loading' 상태인 경우 쿼리 일시 중단
  • true 설정하면 status === 'error' 상태인 경우 런타임 오류 발생
  • default: false

keepPreviousData

  • 새로운 쿼리키 기반으로 데이터를 가져올 때 이전 data를 유지하기 위한 옵션
  • queryKey가 변경되어 새로운 데이터를 요청하는 동안에도 마지막 data의 값을 유지합니다
    • pageNation을 구현할 때, 유용하게 쓰임 ➡ 캐시되지 않는 페이지 호출한 경우 화면의 view 컴포넌트가 사라지는 현상을 방지
    • isPreviusData 값으로 현재 queryKey에 해당하는 값을 확인 할 수 있음

placeholderData

  • 쿼리가 '로드 상태' 데이터에 있으며 initialData가 제공되지 않는 동안 특정 쿼리 관찰자의 자리 표시자로 데이터를 사용

optimisticResults

  • 낙관적으로 설정 ➡ 쿼리가 실제로 가져오기를 시작하기전에 결과를 가져오는 상태

cacheTime

  • default: 5 * 30 * 1000 (5분)
  • unused / inactive 캐시 데이터를 메모리에 유지시킬 시간
  • Infinity 설정 시 쿼리 데이터가 캐시에서 제거되지 않음

retry

  • 요청이 실패한 경우 재요청 실행
  • default: 3

TanStack Query v4 - QueryClientProvider

profile
혼신의 힘을 다하다 🤷‍♂️

3개의 댓글

comment-user-thumbnail
2024년 10월 16일

The Drive Mad blends realistic physics with arcade-style mechanics, allowing for gravity-defying stunts, flips, and jumps that make every level more exciting than the last.

답글 달기
comment-user-thumbnail
2025년 1월 10일

Thanks for your sharing! this is really helpful, I am always trying to escape road like this. https://escaperoads.org

답글 달기
comment-user-thumbnail
2025년 6월 12일

The narrative structure of escape road city 2 is crafted to keep players engaged with its twists and turns. Just when you think you’ve figured everything out, new revelations can change your perspective. How will you adapt to the evolving story as you progress through the game?

답글 달기