React Query 잘 사용하기 - #3. 폴더 구조

YI·2024년 3월 29일
2

React Query

목록 보기
3/3
post-thumbnail

안녕하세요, 이번 글은 'React Query 잘 사용하기' 시리즈의 마지막 글입니다. 이번 글에서는 앞서 설명한 queryKey, Custom hook 등 다양한 React Query 관련 코드를 어떻게 관리했는가에 대해 이야기 해보고자 합니다.

React Query 이렇게 사용했어요

사용 버전 : @tanstack/react-query : v4.35.3

들어가기 앞서..
아래의 내용이 React Query를 사용하는 Best Practice가 아닙니다. 많은 시행착오를 겪으며 나름대로 정립한 React Query 사용법을 공유하는 글 입니다. 건설적인 태클과 지적, 제안은 언제나 환영입니다!

1. Query Key 관리하기
2. Custom hook 사용하기

3. 폴더 구조

React Query를 잘 사용하기 위해 API 호출을 여러 단계로 추상화하고, React Query hook을 Custom hook으로 분리하는 등 다양한 시도를 했습니다. 이 과정에서 이 코드는 어디에 위치하는 것이 좋을 지, 이 코드는 별도의 파일로 분리하는 것이 좋을 지 합치는 것이 좋을 지 등 폴더 구조와 파일 관리에도 많은 고민을 했습니다.

이번 글에서는 제가 어떤 고민을 했고, 어떤 선택을 하였는 지, 채택한 방법의 장점과 단점에 대해 이야기 해보고자 합니다.


① 사용한 폴더 구조 설명
먼저 제가 사용한 폴더 구조를 보여드리겠습니다.
우선 저는 API 호출과 관련된 모든 코드를 src/api 폴더에 위치하도록 하였습니다.

src/api
 ┣ 📂endpoints
 ┗ 📂reactQuery

조금 더 자세히 살펴보자면 아래와 같습니다.

  • /endpoints 폴더
    - Swagger의 Tag를 기준으로 구분된 API의 각 endpoint에 대한 로직이 담긴 파일들을 포함합니다.
    • 각 파일은 하나의 엔드포인드에 대응하며, 해당 파일이 어떤 api를 호출하고, 어떤 HTTP Method를 사용하는 지 알 수 있도록 파일명을 정의했습니다.
  • /reactQuery 폴더
    - React Query 라이브러리와 관련된 코드들을 포함합니다.
    • 애플리케이션 전체에서 사용되는 queryKey, queryClient, useQuery와 useMutation 같은 React Query hook을 각각의 파일로 관리했습니다.
src/api
 ┣ 📂endpoints
 ┃ ┣ 📂artworks
 ┃ ┃ ┣ 📜artworks.d.ts
 ┃ ┃ ┣ 📜index.ts
 ┃ ┃ ┣ 📜useDeleteArtworksCategory.ts
 ┃ ┃ ┣ 📜useFetchAdminList.ts
 ┃ ┃ ┣ 📜usePatchArtworksCategory.ts
 ┃ ┃ ┣ 📜usePostArtworksCategory.ts
 ┃ ┃ ┣ ...
 ┃ ┣ 📂commonCodes
 ┃ ┃ ┣ 📜index.ts
 ┃ ┃ ┗ 📜useFetchCommonCode.ts
 ┃ ┣ 📂typings
 ┃ ┃ ┗ 📜endpoints.ts
 ┃ ┗ 📜index.ts
 
 src/api
 ┗ 📂reactQuery
 ┃ ┣ 📂typings
 ┃ ┃ ┣ 📜query.ts
 ┃ ┃ ┗ 📜queryKeys.ts
 ┃ ┣ 📜index.ts
 ┃ ┣ 📜queryClient.ts
 ┃ ┣ 📜queryKeys.ts
 ┃ ┣ 📜useMutation.ts
 ┃ ┗ 📜useQuery.ts

그리고 각 폴더 아래 index.ts 파일을 포함하여, 폴더 내의 파일들을 하나로 묶어 외부에서 쉽게 가져다 사용할 수 있도록 하였습니다.

예를 들어, artworks 폴더 내의 index.ts 파일을 살펴보면 아래와 같이 이루어져 있습니다.

// artworks/index.ts
export * from './useFetchAdminList.ts';
export * from './useDeleteArtworksCategory.ts';
// 나머지 모든 파일들도 같은 방식으로 export

그리고 endpoints 폴더에도 index.ts 파일이 존재해, endpoints 하위의 모든 폴더와 파일을 하나로 묶어 export 하였습니다.

// endpoints/index.ts
export * from './artworks';
export * from './commonCodes';
// 나머지 모든 폴더,파일들도 같은 방식으로 export

이렇게 하면 외부에서 해당 폴더에 접근할 때 여러 개의 import 문을 작성하는 번거로움 없이 간결하게 코드를 작성할 수 있습니다.

import { useFetchAdminList, useDeleteArtworksCategory } from '@api/enpoints'; 

이러한 구조는 많은 장점을 가져다 주었습니다. 코드의 가독성을 높이고 유지보수를 쉽게하며, 새로운 파일을 추가하거나 기존 파일을 제거할 때도 index.ts 파일만 수정하면 되므로 관리가 편리하다는 장점이 있습니다.

② 장점과 단점
이러한 폴더 구조를 채택함으로써 많은 장점이 있었지만, 이건 좀 불편하다고 느낀 단점도 존재했습니다.

  1. 장점
    • Swagger를 기준으로 endpoints 하위 폴더 구조를 정의하여, 폴더 이름이나 분류 방식에 대한 고민 없이 명확하고 깔끔하게 분리가능하다.
    • 1개의 파일이 1개의 API와 대응되기 때문에 재사용이 편리하고, API에 변경사항이 발생했을 때 1개의 파일만 수정하면 되기 때문에 편리하다.
  2. 단점
    • Swagger의 Tag가 변경된다면, 그에 맞춰 폴더와 파일을 모두 수정해야하는 상황이 생겨 불편할 때가 있다.
    • QueryKey 전체를 하나의 파일에 넣어 관리하다보니 파일이 점차 커져 가독성과 유지보수성이 떨어진다.

③ 개선 방향

위에서 언급한 단점 중, QueryKey를 단 하나의 파일로만 관리하는 방식으로 인한 불편함이 매우 크게 느껴졌습니다. 애플리케이션의 크기가 점차 커질 수록 QueryKey 파일도 점차 커져 마지막 쯤에는 거의 200줄 이상이 넘는 코드를 포함하는 거대한 파일이 되어버렸습니다. 어디 위치에 새로운 쿼리 키를 추가할 지, 기존에 사용하던 쿼리 키는 어디에 위치하는 지를 찾기 매우 번거로웠습니다.

그래서 중앙 집중형 방식의 QueryKey 관리보다는 적절히 나눠서 관리하는 방법이 필요함을 느끼게 되었습니다.

다음에 프로젝트를 진행한다면, 아래와 같이 endpoints 별로 QueryKey를 나누어 관리할 것 같습니다.

src/api
 ┣ 📂endpoints
 ┃ ┣ 📂artworks
 ┃ ┃ ┣ 📜artworks.d.ts
 ┃ ┃ ┣ 📜index.ts
 ┃ ┃ ┣ 📜artworks.keys.ts
 ┃ ┃ ┣ ...

artworks 관련 api 호출을 모두 관리하는 artworks 폴더 안에서 artwork.keys.ts 라는 별도의 파일로 QueryKey를 관리하는 것 입니다. 이렇게 하면, 각 endpoints 별로 QueryKey를 관리할 수 있기 때문에 적절한 수준의 모듈화를 통해 유지보수에도 효과적일 것 입니다.

그리고 page, limit, sortDirection, sort 등 중복해서 사용되는 parameter는 기존의 src/api/reactQuery/queryKeys.ts에서 선언하고 필요한 곳에서 import하여 사용하면 훨씬 더 간편하게 사용할 수 있으리라 생각됩니다.

물론 위 방법은 모든 프로젝트에 적용할 수 있는 Best Practice는 아니기 때문에 이를 참조하여 봐주시길 바랍니다.


마치며

이번 시리즈에서는 React Query를 상용 프로젝트에 적용하고 개선한 경험을 통해 얻은 인사이트와 시행착오의 경험을 위주로 이야기 했습니다. 이 시리즈가 React Query를 도입하고자 하는 팀에게 조금이나마 도움이 되었기를 바라며 글을 마치도록 하겠습니다. 여기까지 와주신 모든 분들에게 감사의 말을 전합니다. 감사합니다!

Reference

https://www.reddit.com/r/reactjs/comments/18z3nsi/tanstack_react_query_architecture/

profile
Junior Frontend Developer

0개의 댓글