프론트엔드: Tanstack Query 사용에 대하여

@pium · July 23, 2023 · 11 min read

이 글은 우아한테크코스 5기, 피움팀 크루 '참새'가 작성했습니다.

서론

Tanstack: High-quality open-source software for web developers. Headless, type-safe, and powerful utilities for state management, routing, data visualization, charts, tables, and more.
Tanstack: High-quality open-source software for web developers. Headless, type-safe, and powerful utilities for state management, routing, data visualization, charts, tables, and more.

피움의 프론트엔드에서는 서버 상태 관리를 위해 Tanstack Query를 사용하기로 하였다.

이 글에서는 많고 많은 상태 관리 라이브러리 중 Tanstack Query를 사용하기로 결정한 이유를 소개하고자 한다.

설치한 버전: 5.0.0-alpha.86

Tanstack query로 얻을 수 있는 개발적인 이점

코드 간소화와 컴포넌트의 관심사 분리

Tanstack query에서 제공하는 다양한 함수들을 활용하면 비동기 통신의 처리 코드를 선언형으로 만들 수 있다. 또한 Tanstack query가 서버와의 통신을 대신해주기 때문에 컴포넌트의 렌더링 함수는 UI/UX의 구현이라는 보다 근본적인 내용에 집중할 수 있다. 조금 더 풀어서 설명하면 네 가지로 나눌 수 있다.

우선 <Suspense><ErrorBoundary>의 편한 사용이 가능하다. 이 둘을 사용하기 위해서는 각각 promise 또는 error를 throw하는 과정이 필요하다. 특히 error가 아닌 것을 던진다는 생각은 기존의 틀을 깨는 것으로 (eslint에 관련 설정이 있다는 점으로 미루어 볼 때 자주 사용하는 기법이 아니었을 것이다) 새로운 코드를 짜야 한다. Suspense를 설명하는 리액트 공식 문서의 첫 번째 예제에서 Fork를 눌러 Albums.js안의 use()함수를 보면 promise를 던지기 위해 굉장히 재미있는 기법을 사용하고 있다는 걸 확인할 수 있다. 이러한 일련의 과정을 tanstack query가 대신하기 때문에 편리한 사용이 가능하다.

다음으로 낙관적 업데이트를 적용하기에 유리하다. useMutationonSuccess, onError, onSettled와 같은 설정을 이용하면 된다.

세 번째로는 비동기 통신의 결과 타입을 자동으로 추론해준다는 점이다. 따라서 컴포넌트 내부에서 불필요한 타입 가드 및 추론, 강제 타입 지정과 같은 행동을 하지 않아도 되므로 타입스크립트를 더 깔끔하게 사용할 수 있다.

마지막으로 서버 상태 처리를 위한 전역 상태 관리 라이브러리를 도입하지 않아도 된다. 물론 이건 비단 tanstack query만의 장점은 아니다. 하지만 캐싱을 이용해서 전역 상태를 이용하지 않고도 여러 컴포넌트에서 같은 쿼리를 요청했을 경우 추가적인 통신 없이도 정보를 전달받을 수 있다는 점은 매력적이다.

비동기 통신

  1. 캐싱을 지원하기 때문에 서버와의 불필요한 통신을 줄일 수 있다.
  2. 다양한 상황에서 자동 refetch가 가능해서 원한다면 항상 최신 값을 유지할 수 있다.
  3. 여러 컴포넌트가 같은 쿼리를 사용할 때, 해당 쿼리로부터 반환되는 데이터가 바뀌었다면 그 컴포넌트들을 한 번에 업데이트할 수 있다.
  4. 쿼리가 오랫동안 사용되지 않으면 가비지 컬렉터를 자동으로 불러서 정리한다.

다른 라이브러리와의 비교

우리 팀에서는 Recoil 이외의 다른 전역 상태 라이브러리나 서버 상태 라이브러리를 사용해본 경험이 많은 크루가 없어서 간단하게만 비교하였다.

SWR

Next.js 팀에서 만든 서버 상태 관리 라이브러리. 데이터 캐싱이라는 측면에 집중했다. 따라서 다른 라이브러리와 비교했을 때 굉장히 가벼운 편에 속한다.

Tanstack Query

데이터 캐싱뿐만이 아니라 에러 처리나 무한 스크롤과 같은 다양한 기능을 지원한다. 비슷한 기능을 하는 리액트 쿼리의 useQuery와 SWR의 useSWR의 반환값을 확인해보았을 때 받을 수 있는 정보의 양이 차이가 많이 난다. 다양한 상황을 고려한 UI를 보여준다면 Tanstack query를 활용하는 것이 좋겠다는 생각을 했다. 추가적으로 받아온 데이터의 일차 가공이 필요하다면 useQuery에서 selector를 사용할 수 있다는 점도 상대적인 장점이라고 생각한다.

Redux, Recoil 등 다른 전역 상태 관리 라이브러리

현재 피움 서비스 내에서 전역적으로 관리할 값이 많지 않다고 판단하였다.

또한 일반적인 전역 상태 라이브러리의 경우 서버 상태를 나타나기에는 부적절한 것 같다. 특히 Recoil은 selector의 캐시 문제로 인해 사용자의 장바구니 목록처럼 자주 변하는 값을 받아오기 굉장히 힘들었던 기억이 있다.

Tanstack Query로 사용자에게 어떤 서비스를 제공하고자 하는지

우리가 추구해야 하는 것은 기술적 고점이 아니다. 그렇기 때문에 이 라이브러리를 도입해서 사용자에게 어떤 경험을 선사할 수 있을지 고민하였다.

  1. Suspense

    • Suspense는 사용자에게 '지금 무슨 일을 하는 중이다'라는 암시를 준다. 따라서 사용자의 기다리는 시간을 편하게 할 수 있다.
    • 피움 서비스의 '식물 사전' 기능은 공공데이터를 활용한다. 현재 사용하고 있는 공공데이터의 경우 이용에 제약이 없어서 DB에 저장할 수 있다. 만약 그렇지 않아서 항상 백엔드 서버에서 공공데이터 API와의 통신을 추가적으로 진행해야 할 경우 정보를 받아오는 데 시간이 걸린다. 이 때 Suspense를 잘 활용할 수 있을 것이다.
  2. Refetch

    • 피움 서비스는 모바일 환경을 우선적으로 고려하고 있다.
    • 지하철 와이파이처럼 인터넷이 불안정한 곳에서는 요청이 잘 가지 않을 수 있다. 이 때 사용자가 같은 행동을 두 번 하지 않더라도 tanstack query가 자동적으로 요청을 보내서 UX 측면의 개선이 가능하다.
  3. caching

    • '식물 사전 정보'는 변하지 않는 자료이다. 따라서 사용자가 여러 번 요청을 하더라도 매번 같은 정보를 보게 된다. 이러한 요청에 대해서는 staletime을 길게 잡아 캐시를 오래 유지한다면 불필요한 서버와의 통신을 줄이고 사용자 경험도 개선할 수 있다.
    • '내가 키우는 식물 목록'이나 '내가 키우는 식물의 상세 정보'도 사용자가 값을 추가하거나 바꾸지 않는 이상 변하지 않는 값이다. 이 친구들도 적절한 캐싱을 사용하면 서버와의 통신을 줄여 사용자의 대기시간을 줄일 수 있다.
  4. 무한 스크롤

    • 피움에서는 자신의 식물에게 물을 준 날짜들을 기억해서 타임라인 형태로 볼 수 있도록 제공할 계획이다. 타임라인은 시간의 흐름을 나타내기 위한 도구이다. '시간'과 '흐름' 모두 연속성을 띠는 표현인 만큼 무한 스크롤을 이용해 유의미한 경험을 제공할 것이다.

Tanstack Query v5를 사용하게 된 이유

마지막으로 피움 프론트엔드에서 Tanstack query의 다섯 번째 메이저 버전을 사용하기로 한 이유를 짧게 남긴다. Tanstack query v5는 획기적인 변화가 있고, alpha 단계이다.

  1. 어차피 버전은 5로 흘러간다. 피움 프론트엔드의 세 크루 모두 Tanstack query를 처음 배우는 단계라면 굳이 역사의 뒤안길로 흘러갈 v4부터 배울 필요는 없다고 생각한다.
  2. 문서를 살펴본 결과 v5의 '획기적인 변화'는 대부분 기존의 불필요하거나 문제를 일으키기 쉬운 기능을 제거하는 것이었다. 따라서 만약 v4를 학습해야 한다면 기존의 v5 공부 내용에서 덧붙이는 방법으로 가능할 것이다.
  3. 현재 피움 서비스에서는 복잡한 서버와의 데이터 통신은 없을 것 같다. 따라서 alpha 단계이기 때문에 무언가가 안 되는 상황은 없을 것으로 예상된다.
@pium
우아한테크코스 5기 피움팀 기술 블로그입니다.