React-Query를 Next.js와 함께 사용해보자 Part I.

Paul WooJung Kim
kmong
Published in
9 min readApr 19, 2022

--

안녕하세요!
크몽의 푸른피, 떠오르는 블루칩 Blue(블루)입니다.

Next JS & React Query

Next.js는 크몽 프론트엔드팀의 메인 프레임워크입니다. 서버 사이드 렌더링이 주는 이점이 매우 크기 때문에 사용하고 있습니다.

React-Query는 비동기 로직을 쉽게 다룰 수 있도록 도와주는 라이브러리이며 Next.js와의 궁합이 좋아서 사용하고 있습니다.

사내 스터디를 통해 React-query를 보다 더 잘 사용하기 위한 고민을 했고 가장 좋은 스터디 방법이라고 생각하는 공식 문서 정독과 사용 예시들을 많이 찾아봤습니다.

하지만 예시들은 주로 클라이언트 사이드에서 사용하는 방법이기 때문에 Next.js 환경에서 React-Query를 잘 사용하는 방법은 직접 테스트 해보면서 알아가야 했습니다. 이러한 과정을 통해 알아낸 내용을 공유하고자 합니다.

공식 문서에 따르면 React-Query는 두 가지의 방법으로 prefetching을 지원합니다.

  1. initialData
  2. 서버에서 캐시를 dehydrate 후 클라이언트에서 hydrate를 하는 방식

첫 번째 방법의 사용법은 간단하지만, 클라이언트 사이드에서 해당 데이터를 사용하는 컴포넌트까지 props로 넘겨주어야 하는 비효율적인 작업이 동반됩니다.

두 번째 방법은 위와 같은 비효율적인 작업은 없지만 프론트에서 셋업 해야 할 것 들이 있습니다.

크몽에서는 두 번째 방법을 사용하여 prefeching을 합니다.

_app.tsx

공식문서에서 알려주는 사용 방법과 다른점은 없습니다.

크몽의 프로젝트 의뢰 상세 페이지

의뢰 상세 테스트 페이지

크몽에서는 검색을 통해 다양한 서비스를 이용할 수 있지만 프로젝트를 직접 의뢰할 수도 있습니다.

해당 페이지는 유저가 직접 의뢰한 의뢰 상세 내용을 보여주는 페이지입니다.

또 한 전문가인 유저는 해당 페이지를 통해서 프로젝트 진행 제안을 할 수 있습니다.

페이지 진입 후 바로 보이는 내용은 프로젝트 의뢰 상세 정보이고 오른쪽 상위에 위치한 제안하기 버튼을 클릭하면 모달이 열리고 제안할 때 필요한 본인 자신의 프로필이 보인다.

그 때문에 해당 페이지에서는 두 가지의 데이터를 서버에 요청하여 사용합니다.

getServerSideProps
  1. 프로젝트 의뢰 상세 정보를 조회하는 API
  2. 본인의 프로필 정보를 조회하는 API

이 두 가지의 정보를 prefetching을 통해 조회합니다.

이렇게 prefeching을 하여 서버 사이드 렌더링을 해주면 페이지에 진입 했을 때 로딩 처리 없이 원하는 정보를 바로 보여 줄 수 있습니다. 이것이 바로 서버 사이드 렌더링의 장점입니다.

Cache & Fetching & Stale & Refetching

CacheTime은 inactive 상태일 때 카운트 다운이 시작되며 staleTime은 active 상태일 때 카운트 다운을 합니다.

공식문서에 따르면 CacheTime의 default 값은 5분이고 staleTime의 default 값은 0입니다.

다시 말해 cache 데이터는 5분뒤 초기화 되어 fetching을 다시 해야 하는 상태가 된다는 말이며 stale 데이터는 fetching 후 바로 refetching을 할 수 있는 상태가 된다는 뜻입니다.

만약 staleTime을 1분으로 설정하면 1분 동안은 refetching이 절대로 일어나지 않습니다.

refetching은 다양한 옵션을 통해 설정할 수 있습니다.

대표적으로 refetchOnMount (컴포넌트가 mount 되었을 때), refetchOnWindowFocus (브라우저 window가 focus 되었을 때), refetchOnInterval (설정한 interval에 따라 실행) 등이 있습니다.

react-query devtools을 적용한 의뢰 상세 페이지

react-query devtools를 사용하면 데이터의 상태를 쉽게 확인할 수 있습니다.

첫 번째 데이터인 의뢰 상세 데이터는 해당 query를 사용하는 컴포넌트가 렌더링 되었기 때문에 active 상태이며 prefetching을 통해 fetching이 되었기 때문에 데이터는 바로 stale 되었습니다.

두 번째 데이터인 프로필 상세 데이터는 아직 렌더링이 되지 않았기 때문에 inactive 상태입니다.

해당 페이지에서 의뢰 상세 데이터는 무조건 렌더링이 되어있기 때문에 cache 데이터는 초기화가 되지 않습니다.

따라서 이 경우엔 한번 서버 사이드 렌더링을 하고 나면 fetching이 다시 일어나지 않습니다.

하지만 여기서 문제가 있습니다. 만약 의뢰인이 의뢰 내용을 변경하면 어떻게 될까요?

refetching 처리는 선택이지만 데이터의 성격에 따라 아닐 수도 있다

해당 페이지를 refresh 하지 않는 이상 절대로 의뢰인이 수정한 내용을 알 수 없습니다.

이것은 HTTP 통신의 한계라고 할 수 있습니다.

하지만 React-Query는 refetching 이라는 기능을 통해 서버와 클라이언트간의 데이터가 최대한 동기화 될 수 있도록 도와줍니다.

React-Query의 refetching과 관련된 옵션들의 default 값은 주로 true로 설정되어 있습니다. 그만큼 React-Query팀은 동기화를 중요하게 생각하는 것을 알 수 있습니다.

refetchOnMount 옵션을 설정한 query

의뢰 상세 데이터 쿼리는 refetchOnMount 옵션 정도만 제외하고 모두 default 상태로 설정해 놓았습니다.

refetching…

이제 refetching을 통해 서버와 데이터 동기화를 할 수 있게 되었습니다.

코드를 보면 isRefetching을 이용해 refetching시 스켈레톤 UI를 보여주도록 만들었습니다.

보다 더 완벽한 서버 데이터와의 동기화를 원한다면 refetchOnInterval 과 같은 옵션으로 주기적으로 동기화를 시켜줄 수 있습니다. 페이지와 데이터의 성격에 따라 설정해주면 좋습니다.

전문가 프로필 모달

제안하기 버튼을 누르면 열리는 전문가 프로필 모달

해당 모달에서 prefetching으로 가지고 온 두 번째 데이터(프로필 정보)를 사용합니다.

모달을 열면 loading UI 없이 데이터를 바로 보여줄 수 있어 사용자 경험이 좋습니다.

여기서 주의해야 할 점이 있습니다. prefetching을 하여 데이터를 가지고 오더리도 클라이언트에서 다시 fetching을 해야 하는 경우가 있습니다.

prefetching을 하더라도 fetching을 다시 해야 하는 경우

페이지 진입 후 해당 데이터를 사용하는 컴포넌트가 렌더링이 되지 않았기 때문에 해당 데이터는 inactive인 데이터입니다. 그 말인즉슨 cacheTime은 카운트 다운을 하고 설정한 cacheTime(default 5분) 이후로 캐시 데이터가 초기화 됩니다.

이렇게 초기화 된 상태로 해당 모달을 열면 캐시 데이터가 없기 때문에 데이터에 바로 접근해서 사용하면 에러가 발생합니다.

따라서 React-Query에서 제공하는 isLoading과 같은 fetching 상태를 알 수 있는 옵션을 사용해 에러로부터 방어를 해주어야 합니다. 혹은 데이터가 없을 때를 대비한 처리를 해야 합니다.

fetching…

fetching시 skeleton UI를 보여주도록 했습니다.

해당 모달에선 refetching 여부를 다루지 않았습니다. 중요하지 않기 때문입니다. 본인의 프로필을 편집하려면 페이지 이동이 필요하기 때문에 해당 페이지로 다시 돌아왔을 땐 수정한 프로필로 동기화가 잘 되어있을 것입니다.

따라서 refetch 옵션들을 꺼버리거나 staleTime을 infinity로 설정하면 됩니다. 크몽에서는 옵션 설정을 변수로 만들어 유틸리티 파일에서 관리하고 사용합니다.

그 밖에

prefetching은 에러를 catch 하지 못합니다. 만약 prefetching시 에러가 발생하면 클라이언트에서 다시 fetching을 하게 됩니다. 그런데도 에러가 발생할 수 있으니 이러한 점을 대비해 isError과 같은 React-Query가 제공하는 옵션으로 에러 처리를 해주는것이 좋습니다.

SUMMARY

  1. cacheTime은 inactive 상태일 때 카운트 다운하고 staleTime은 active 상태일 때 카운트 다운한다.
  2. 페이지와 데이터의 성격에 따라서 refetching 처리를 해주자.
  3. prefetching을 한다고 해도 클라이언트에서 fetching을 다시 해야 하는 경우가 있다. 데이터가 무조건 있다고 생각하면 안 된다.

Part II에서는 next 서버에서 queryClient 인스턴스를 효율적으로 생성하고 관리하는 방법에 관하여 설명하고자 합니다.

--

--

Frontend Engineer @Kmong | You don’t make mistake, mistake makes you 🚀