[TOJ] - React-Query 도입 배경 및 적용 해보기

조민호·2023년 11월 9일
0
post-custom-banner


도입 배경

리액트 쿼리를 사용하게 되는 이점은 정말 다양하다

  1. API로부터 데이터를 가져온 후 이를 자동으로 캐시한다.

    만약 사용자가 다른 페이지로 이동했다가 다시 돌아오거나, 동일한 데이터를 필요로 하는 다른 컴포넌트에서 쿼리를 실행할 때,

    캐시된 데이터를 즉시 사용할 수 있으므로 새로운 네트워크 요청을 보낼 필요가 없는 것이다.

  2. 데이터가 변경될 때 필요한 컴포넌트만 리렌더링되므로

    불필요한 렌더링을 줄일 수 있는 최적화된 렌더링이 가능하다

  3. isLoading, isFetching 등의 값들을 통해 데이터 상태 등을 쉽게 추적 하고 관리할 수 있어, 비동기 쿼리 상태의 간편한 추적이 가능하다

  4. 서버에서 데이터를 업데이트한 후, 클라이언트에 있는 여러 컴포넌트들이 최신 데이터를 반영해야 한다면,

    invalidateQueries 를 호출하여 관련 쿼리들을 새로고침함으로써 데이터를 즉시 동기화할 수 있다

    만약, axios 만 사용했다면 이 역시 api를 다시 호출한 다음에 상태를 업데이트해줘야 하는 번거로움이 있다

그 중에서 해당 프로젝트에 React-Query를 도입하게 된 이유는 1,2번의

이유 때문이었다.

(모든 명분을 전부 만족시킬때 비로소 사용하기 보단 차츰차츰 사용해 가면서 발전된 DX들을 경험해 볼 예정이다)




프로젝트에 적용하기

현재 라우팅 구조의 일부를 보면 아래와 같다

<Route path="/*" element={<CommonLayoutWithMenus />}>
      <Route path={`${PAGE_URL.Problem}/:problemId`} element={<Switch.ProblemPage />} />
      <Route path={`${PAGE_URL.Submit}/:problemId`} element={<Switch.Submit />} />
      <Route path={`${PAGE_URL.Status}`} element={<Switch.Status />} />
</Route>
  1. 메인 페이지에서 원하는 문제를 선택하게 되면 선택한 문제의 정보를 제공 해주는

    문제 정보 페이지(PAGE_URL.Problem)로 진입하게 된다

  2. 여기서 문제의 정보를 제공하고 제출 페이지(PAGE_URL.Submit) ,

    제출현황 페이지(PAGE_URL.Status) 로 이동할 수가 있으며

  3. 해당 페이지들은 레이아웃으로 지정한 CommonLayoutWithMenus.tsx가 이들을 감싸고 있다

왜 저렇게 구성을 했냐 하면 CommonLayoutWithMenus는 문제 관련 페이지들에

항상 존재하는 메뉴 바의 형태를 지니고 있다

💡 프로젝트 전체에 사용되는 네비게이션바 와 별개로 사용되는 메뉴바 이다

메인 페이지에서 문제를 선택하게 되면 진입하는 문제 제공 페이지(PAGE_URL.Problem)

제출 페이지(PAGE_URL.Submit)



메인페이지에서 특정 문제를 클릭해서 진입하게 되면

이 페이지 내부에서 문제 정보를 보거나 , 문제를 제출하거나 등등의 기능을 사용할 수 있는데

이 기능들을 사용할 수 있게 사용되는 메뉴 바가 되는 것이다

그러므로 각 페이지에서 공통된 메뉴 바를 띄워줘야 했기 때문에 레이아웃 형태로 사용했다.

그런데 , 메뉴바에는 단순히 각 버튼이 서로의 페이지로 리다이렉션만 해주는 기능만 있는 것은

아니다

위의 사진에도 볼 수 있듯이 메뉴 바의 가장 왼쪽 버튼에는 아래의 정보들이 필요하다

  • 현재 선택한 문제 이름
  • 현재 선택한 문제 난이도 (연두색이 easy)
  • 현재 선택한 문제 번호

즉, 메뉴 바 역시 현재 선택한 문제들의 데이터 상태를 가지고 있어야 하는 것이다

이를 구현하기 위해 가장 간단한 방법은 그냥 해당 페이지들에 접근 할 때마다
계속해서 CommonLayoutWithMenus 에서 선택한 문제에 대한 API를 호출하고 상태를 업데이트 하면 된다

그렇지만 이는 매우 비효율적이다

같은 문제 안에서 제출하기 , 답안보기 , 내 제출 버튼을 클릭하면서 페이지를 이동하게 되면

( 라우터의 PAGE_URL.Problem , PAGE_URL.Submit , PAGE_URL.Status )

동일한 데이터임에도 계속해서 API를 호출해야 하기 때문이다



그래서 도입해보게 된 것이 React-Query이다

  • 최초 문제 관련 페이지에 진입하게 되면
  • 문제 관련 페이지들은 감싸는 CommonLayoutWithMenus 와 관련 페이지들에서 React-Query를 사용하고
  • 페이지간 전환이 발생할 때마다 기존에 캐싱된 데이터를 이용하는 것이다

대략적인 그림을 그려보면 아래와 같다

// 문제 관련 페이지 구성
|----------------------------------------------------------------|
|                                                                |
|  메뉴바(CommonLayoutWithMenus) // 1차로 useQuery 사용           
|                                                                |
|----------------------------------------------------------------|
|                                                                |
|  메뉴바 클릭시 이동되는 각 페이지들                              |
|  (PAGE_URL.Problem , PAGE_URL.Submit , PAGE_URL.Status)        |
|  // useQuery로 CommonLayoutWithMenus에서 사용한 캐싱 데이터 사용
|                                                                |
|                                                                |
|----------------------------------------------------------------|

  1. 최초에 메인페이지에서 문제를 선택하면 메뉴바인 CommonLayoutWithMenus에서

    React-Query로 데이터를 호출을 한다

    • checkURL함수는 올바른 URL인지 유효성 체크를 하는 것이다.

    • 현재 선택된 문제 ID는 로컬스토리지에도 추가 해 놓는다


  2. 문제 ID를 기반으로 해당 데이터를 캐싱해 두면 동일한 문제 페이지 내부에서는

    더이상 API를 호출하지 않고 캐싱된 데이터를 그대로 사용할 수 있기 때문이다

    아래 코드는 선택한 문제의 정보를 제공 해주는 페이지(PAGE_URL.Problem)이다

    여기서 URL은 problem/:problemId 형태이므로 문제ID값을 가져와서
    useQuery로 문제 데이터를 호출 하는데 , 실제로는 API를 호출하지 않고
    CommonLayoutWithMenus에서 캐싱된 데이터를 그대로 가져와서 사용하는 것이다.

    아래 코드는 제출 페이지(PAGE_URL.Submit) 코드이다

    여기서도 마찬가지로 URL로 문제 ID값을 가져와서 useQuery로 캐싱된 데이터를 그대로 가 져와서 사용한다

post-custom-banner

0개의 댓글