React Query 정리

개미·2023년 11월 9일
1
post-custom-banner

React Query란?

  • 서버 상태 관리 라이브러리 = 즉, 서버에서 받아온 데이터를 관리하는 라이브러리
  • 물론, 그냥 fetch를 사용해도 되지만, React Query는 많은 옵션을 가지고 있어 상황에 맞게 적절한 서버 데이터 상태 관리가 가능하다. 즉 React Query를 사용하면 코드가 훨씬 간결해지는 것을 경험할 수 있다.

내가 React Query를 썼던 첫 이유…

Redux를 공부하다가 React-Query에 대해 알게 되었다. React Query의 속성에 isLoading이 있는 것을 알게 되었고, 코드를 훨씬 간결화할 수 있어 프로젝트에 도입하게 되었다.

하지만…

정확하게 React Query를 이해하지 못하고 사용하다 보니 예상치 못한 이슈들이 발생했다.

다른 탭 이동 후 다시 돌아 왔을 때, 다시 api 호출하는 것을 발견했다. api 호출이 필요없는 시점이기에 네트워크 비용을 아끼기 위해서 원인을 파악하고자 하였다.

그러다가 React Query를 자세히 공부하게 되었고, 그 내용을 지금 정리하려 한다.

useQuery

const { isLoading, isError, data, error } = useQuery({
    queryKey: ['todos'],
    queryFn: fetchTodoList,
  })

queryKey

queryKey는 unique 해야 한다. 배열도 가능하다

해당 키는 refetching, caching, 그리고 query를 공유할 때 쓰인다.

queryFn에 쓰이는 변수가 있다면 정의를 해주어야 한다.

function Todos({ todoId }) {
  const result = useQuery({
    queryKey: ['todos', todoId],
    queryFn: () => fetchTodoById(todoId),
  })
}

queryFn

api를 fetch하는 코드를 여기에 작성하면 된다.

{ isLoading, isError, isSuccess, data, error, isFetching }

useQuery가 제공하는 속성이다. 이것이 너무 유용해서 나는 사용하게 되었다.

  • isLoading: 아직 데이터가 없는 상태이다
  • isError: queryFn에서 에러가 발생한 상태이다.
  • isSuccess: queryFn이 성공적으로 끝난 상태이다.
  • error: isError 상태에서 error를 사용할 수 있다.
  • data: isSuccess 상태에서 data를 사용할 수 있다.
  • isFetching: 쿼리가 다시 fetch될때 있는데, 그때마다 isFetching은 true가 된다. isLoading은 데이터가 없을 때만 false이고, isFetching은 fetch가 끝나면 false가 되는 것이다.

옵션

옵션은 굉장히 많다. (사실 위의 속성도 저것보다 훨씬 많다.) 더 많은 내용은 공식문서를 참고하면 될 것 같고, 지금은 내가 잘 사용하는 or 사용할 것 같은 옵션들을 정리해보려한다.

cacheTime

이해하기 어려웠는데 한 블로그를 보고 이해가 쉽게 되었다! (참고에 걸어둠)

모든 컴포넌트가 마운트 해제되는 시점에서 비활성 상태로 전환되고 캐싱한다는 의미이다. 즉 쿼리를 사용하는 모든 컴포넌트가 현재 화면에 없다면 그 쿼리는 비활성 상태가 된다. 그 비활성 상태가 되고 난 이후 얼마 동안 데이터를 캐싱하고 있느냐이다.

cacheTime의 default 값은 5분이다.

지금은 gcTime으로 변경되었다. 가비지 콜렉터와 비슷한 느낌이라서!

staleTime

윈도우에 다시 포커스되었을 때나, 컴포넌트가 다시 마운트될 때나, 네트워크가 재연결되었을 때 등의 트리거가 발생했을 때 다시 페치한다.

staleTime의 default 값은 0이다. 즉, 위와 같은 트리거가 발생하였을 때 항상 다시 페치하지만, staleTime을 조정해주면 그 시간동안은 다시 페치하지 않는다.

refetchOnwindowFocus

사용자가 현재 화면에서 포커스를 잃었다가 다시 돌아오면 fetch를 한다. 이 것 때문에 탭 전환시 지속적인 네트워크 요청이 발생한 것이었다.

default 값은 true이다.

+refetchOnMount, refetchOnReconnect 도 이름에서 알 수 있듯이 마운트 할때마다, 네트워크가 재연결 될때마다 fetch한다. 즉, windowFocus, Mount, Reconnect가 stale 상태인 것!

enabled

true일 경우 useEffect 내의 fetch처럼 매번 렌더링시에 실행된다. 만약, useQuery를 이벤트 발생 시에 쓰고 싶다면 enabled를 false로 설정하고, refetch 속성을 사용하여 useQuery를 실행시킬 수 있다. 이번에 공부하며 알게 되었는데 api를 가독성있게 정리하는데 유용하게 잘 사용될 것 같다.

const { data, refetch } = useQuery('search', getSearch,
	{
		enabled: false
	}
);

아니면 id가 있을 경우에만 실행시킬 수도 있다.

const {
  status,
  fetchStatus,
  data: projects,
} = useQuery({
  queryKey: ['projects', userId],
  queryFn: getProjectsByUser,
// The query will not execute until the userId exists
  enabled: !!userId,
})

default 값은 false이다.

onSuccess, onError

fetch에 성공 혹은 실패시에 실행할 코드를 작성할 수 있다.

{
    onError: (error) => {
        console.error('논문 정보를 불러오는 데 실패하였습니다:', error)
        Sentry.captureException(error)
    }
}

initialData

데이터를 fetch하기 전에 표시할 데이터에 대한 초기값을 설정해줄 수 있다.

useMutation

useQuery는 get 요청을 할 때 쓰인다. post/put/dele는 useMutation을 사용하면 된다!

내가 실제 쓰고 있는 코드를 발췌해왔다.

const { mutate } = useMutation(
    (payload: paperLikePayload)=> postApi(api, `/api/paperlikeonoff`, payload)
    .then(async response => {
        if (response.status === 401) {
            await refreshApi(api, notify, navigate)
          } else if (response.status === 400) {
            navigate(`/home`)
          }
    })
    .finally(()=>{
        setOpen(false)
        setPaperIdArray(prevArray => [...prevArray, payload.paperId])
    }), {
        onError: (error) => {
            console.log("관심 논문 삭제에 실패하였습니다", error)
            Sentry.captureException(error)
        }
    }
)

참고

https://tanstack.com/query/v4/docs/react/overview

https://velog.io/@jewoo/React-Query-파헤치기

https://ttaerrim.tistory.com/53

profile
개발자
post-custom-banner

0개의 댓글