tanstack-query 사내 도입 회고 1편

2023-01-01 오후 5:07:50
React.js
react-query
tanstack-query
tanstack-query 사내 도입 회고 1편

도입 배경

1. 첫 인상

취준 당시 develogger 프로젝트를 처음 개발할때 tanstack-query를 도입해서 사용했었다.
이때 tanstack-query를 도입하게 된 이유도 많은 고민이 있었다.
먼저 대부분의 상태가 백엔드에서 받아오는 데이터에 의해 정해진다고 판단하고
로컬에서만 관리되는 전역 state는 가벼운 라이브러리(zustand)를 선택했다.

그리고 swr, rtk-query, tanstack-query 3가지를 모두 살펴본 후
tanstack-query가 가장 사용률이 높고, 세분화되고 많은 기능을 제공해주는것으로 보여 선택했다.
( 각 라이브러리들의 상세 비교 표 )

그런 사용경험을 가진 상태로 취업 후 회사 프로젝트에 참여하게 되었는데,
여기서는 직접 fetch함수를 래핑해서 사용하는 일반적인 방식으로 개발을 진행했다.
( 그때 당시 아직 tanstack-query가 보편화된 느낌은 아니였다. )
이때, 생각보다 tanstack-query가 제공해주는 편리함을 꽤나 체감했었다.

2. 사용 경험

develogger 프로젝트는 github에 public으로 공개되어 있어서 코드를 볼 수 있다. ( 링크 )
살펴보면 tanstack-query를 사용하면서 구조에 대해 고민했던 부분이 있는데,

어떻게 백엔드에 요청할 각 api 주소와, tanstack-query key를 어떻게 맵핑해서 사용할까?

에 대한 부분이다.

swr의 경우 api url이 곧 key가 되는 방식이기때문에 이런 고민이 필요없었다.
develogger는 혼자 개발했지만, 다른사람과 협업 시 분명히 중구난방으로 사용되어
관리가 어려울것같았다.
그래서 생각해낸 방안은 아래와 같다.

// utils/queryAPI.ts // examples import axios from 'axios'; ... const api = axios.create({ baseURL: process.env.NEXT_PUBLIC_API_URL, }); ... /** * 포지션별 모든 Tags info 가져오기 */ export const getAllTagInfoApi = { key: 'getAllTagInfoApi', apiCall: async (Authentication?: any): Promise<IAllTagInfoType[]> => { return await api .get( `v1/blog/tags-info`, typeof Authentication === 'string' ? { withCredentials: true, headers: { Cookie: `Authentication=${Authentication || ''}`, }, } : { withCredentials: true, } ) .then((response) => response.data.tagInfoResult) .catch((err) => { console.log(err.message); return false; }); }, };

위 예시 처럼 queryAPI.ts를 만들고,
api별로 키와 fetch함수를 묶어서 객체로 export시켜주었다.
이렇게하면 useQuery를 사용하는 곳에서 getAllTagInfoApi등을 import해 사용하면
key와 api가 항상 맵핑 된것을 사용할 수 있다.

// Tag data 가져오기 const { data, refetch, isFetching } = useQuery(getAllTagInfoApi.key, getAllTagInfoApi.apiCall);

지금 생각해보면 파라미터에 따라 캐싱도 되지 않고,
설정도 공통화 및 개별화 하기 어려운 구조지만
나름 고민했던 흔적이 보이는것같다.

그리고, 개발하면서 각 api 호출시 tanstack-query가 제공해주는 훅(useQuery 등)들을 사용하면
statusCode에 따라 data, refetch, isFetching, isLoading ...등 수많은 정보들을 제공해주는데
이 구조는 직접 구현하려면 많은 코드작성이 필요하기 때문에 매우 편리하게 느껴졌다.
또한, 기본적으로 제공해주는 devtools도 잘 구현되어있어 디버깅도 경험이 좋았다.

3. 필요성

사내 프로젝트들은 javascript와 typescript가 섞여있었고,
지도, 차트 등 데이터가 많고 광범위했기에 fetch시 최적화가 많이 필요했다.

모든 프로젝트에 도입할 필요성은 낮아보였고,
언젠가 어드민 등 작은 프로젝트는 도입해보는 것 정도는 괜찮다고 생각을 하고있었다.

그러던 중 새로운 웹 프로젝트를 하게되었는데,
2명이서(백엔드 1명, 프론트1명) MVP를 개발해야 했다.

전체를 typescript 프로젝트로 구성하고,
먼저 rtk-query와 code-generator(이하 codegen)를 도입했다.
( codegen에 대한건 따로 포스트 작성 예정 - 스웨거 명세를 받아 프론트에 필요한
typescript 코드를 자동으로 생성해주는 방식)

codegen 도입을 언급하는 이유는 tanstack-query를 도입하게 된 이유로 연결된다.

타 프로젝트에서 rtk를 쓰고있고(눈에 익히기 위해),
rtk-query에서 기본적으로 제공해주는 codegen이 있어서 rtk-query를 선택했었다.

이 프로젝트에 구조를 먼저 잘 잡아두면 codegen을 다른 프로젝트에도 도입할 때
예제 및 설득에 활용이 될 수 있다고 생각했다.

백엔드 개발자분과 스웨거 설정에 대한 협의를 하고,
codegen을 도입해보니 실제로 엄청난 분량의 코드를 자동으로 생성해 쓸 수 있었다.

이후 MVP개발이 완료되고, 나는 원래있던 React-Native(이하 RN)프로젝트로 돌아오게 되었다.
codegen을 도입했던 경험을 공유해서 RN프로젝트에도 도입하게 되었다.

그런데 문제가 있었다.
rtk-query가 tanstack-query와 같은 역할을 하고 있었지만
RN에서 디버깅 할 수 있는 devtools를 제공하지 않았고,
codegen으로 출력된 output의 폴더 구조, 쿼리키 등 커스터마이징 기능이 생각보다 부족했다.

그래서 다른 codegen 방식을 리서칭 하던 중 Orval 이라는걸 발견했다.

Orval - Motivation.
I often use a swagger as contract between the frontend and backend team. And before Orval, I used the swagger editor or swagger codegen but >that wasn't enough for my need. That's why I started Orval.

살펴보니 rtk-query codegen과 rtk-query를 사용하면서 불편했던 모든 문제를
Orval, tanstack-query을 도입하면 해결이 가능했다.

아래는 당시 rtk-query 에서 tanstack-query로 마이그레이션 하기 전
장단점 비교를 위해 정리했던 내용이다.

RTK-Query

  • codegen사용시 생성되는 tag로는 캐싱 관리가 어렵다.
  • 타입이 불필요하게 중복 생성되는 문제로 tag별로 query hook을 분리하여 생성하기 어렵다.
  • remote-state debugger가 웹에서만 지원한다.
  • 앱 활성화시 refetch 기능 제공 X
  • codegen 한글 유니코드로 만들어지는 문제
  • 백엔드에서 작성한 주석이 코드에 포함되지 않음.

Tanstack-Query ( Orval )

  • model 폴더에 타입을 공통으로 생성하여 중복 x
  • 백엔드에서 분리 기준으로 잡은 tag별로 query hooks 분리 가능
  • remote-state debugger 가능 (flipper 플러그인 사용)
  • 캐싱관리를 할 수 있는 Key 자동 생성(api url)
  • 앱 활성화시 refetch 기능 제공 O
  • 오픈소스 참여도가 더 활성화 되어있다.
  • codegen 한글 정상 생성됨.
  • 백엔드에서 작성한 주석이 코드에 포함됨.
  • api가 나온상태에서 더미데이터 주입 가능한 구조 제공

그리하여 사내에서 RN프로젝트에 처음으로 tanstack-query를 도입을 시도하게 되었다.

2편에서 계속...

User Profile Icon
LKHcoding
Front-End Developer