리액트 쿼리를 사용하게 되는 이점은 정말 다양하다
API로부터 데이터를 가져온 후 이를 자동으로 캐시한다.
만약 사용자가 다른 페이지로 이동했다가 다시 돌아오거나, 동일한 데이터를 필요로 하는 다른 컴포넌트에서 쿼리를 실행할 때,
캐시된 데이터를 즉시 사용할 수 있으므로 새로운 네트워크 요청을 보낼 필요가 없는 것이다.
데이터가 변경될 때 필요한 컴포넌트만 리렌더링되므로
불필요한 렌더링을 줄일 수 있는 최적화된 렌더링이 가능하다
isLoading
, isFetching
등의 값들을 통해 데이터 상태 등을 쉽게 추적 하고 관리할 수 있어, 비동기 쿼리 상태의 간편한 추적이 가능하다
서버에서 데이터를 업데이트한 후, 클라이언트에 있는 여러 컴포넌트들이 최신 데이터를 반영해야 한다면,
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>
메인 페이지에서 원하는 문제를 선택하게 되면 선택한 문제의 정보를 제공 해주는
문제 정보 페이지(PAGE_URL.Problem)로 진입하게 된다
여기서 문제의 정보를 제공하고 제출 페이지(PAGE_URL.Submit) ,
제출현황 페이지(PAGE_URL.Status) 로 이동할 수가 있으며
해당 페이지들은 레이아웃으로 지정한 CommonLayoutWithMenus.tsx가 이들을 감싸고 있다
왜 저렇게 구성을 했냐 하면 CommonLayoutWithMenus는 문제 관련 페이지들에
항상 존재하는 메뉴 바의 형태를 지니고 있다
💡 프로젝트 전체에 사용되는 네비게이션바 와 별개로 사용되는 메뉴바 이다메인 페이지에서 문제를 선택하게 되면 진입하는 문제 제공 페이지(PAGE_URL.Problem)
제출 페이지(PAGE_URL.Submit)
메인페이지에서 특정 문제를 클릭해서 진입하게 되면
이 페이지 내부에서 문제 정보를 보거나 , 문제를 제출하거나 등등의 기능을 사용할 수 있는데
이 기능들을 사용할 수 있게 사용되는 메뉴 바가 되는 것이다
그러므로 각 페이지에서 공통된 메뉴 바를 띄워줘야 했기 때문에 레이아웃 형태로 사용했다.
그런데 , 메뉴바에는 단순히 각 버튼이 서로의 페이지로 리다이렉션만 해주는 기능만 있는 것은
아니다
위의 사진에도 볼 수 있듯이 메뉴 바의 가장 왼쪽 버튼에는 아래의 정보들이 필요하다
즉, 메뉴 바 역시 현재 선택한 문제들의 데이터 상태를 가지고 있어야 하는 것이다
이를 구현하기 위해 가장 간단한 방법은 그냥 해당 페이지들에 접근 할 때마다
계속해서 CommonLayoutWithMenus 에서 선택한 문제에 대한 API를 호출하고 상태를 업데이트 하면 된다
그렇지만 이는 매우 비효율적이다
같은 문제 안에서 제출하기 , 답안보기 , 내 제출 버튼을 클릭하면서 페이지를 이동하게 되면
( 라우터의 PAGE_URL.Problem , PAGE_URL.Submit , PAGE_URL.Status )
동일한 데이터임에도 계속해서 API를 호출해야 하기 때문이다
그래서 도입해보게 된 것이 React-Query이다
대략적인 그림을 그려보면 아래와 같다
// 문제 관련 페이지 구성
|----------------------------------------------------------------|
| |
| 메뉴바(CommonLayoutWithMenus) // 1차로 useQuery 사용
| |
|----------------------------------------------------------------|
| |
| 메뉴바 클릭시 이동되는 각 페이지들 |
| (PAGE_URL.Problem , PAGE_URL.Submit , PAGE_URL.Status) |
| // useQuery로 CommonLayoutWithMenus에서 사용한 캐싱 데이터 사용
| |
| |
|----------------------------------------------------------------|
최초에 메인페이지에서 문제를 선택하면 메뉴바인 CommonLayoutWithMenus에서
React-Query로 데이터를 호출을 한다
checkURL함수는 올바른 URL인지 유효성 체크를 하는 것이다.
현재 선택된 문제 ID는 로컬스토리지에도 추가 해 놓는다
문제 ID를 기반으로 해당 데이터를 캐싱해 두면 동일한 문제 페이지 내부에서는
더이상 API를 호출하지 않고 캐싱된 데이터를 그대로 사용할 수 있기 때문이다
아래 코드는 선택한 문제의 정보를 제공 해주는 페이지(PAGE_URL.Problem)이다
여기서 URL은 problem/:problemId 형태이므로 문제ID값을 가져와서
useQuery로 문제 데이터를 호출 하는데 , 실제로는 API를 호출하지 않고
CommonLayoutWithMenus에서 캐싱된 데이터를 그대로 가져와서 사용하는 것이다.
아래 코드는 제출 페이지(PAGE_URL.Submit) 코드이다
여기서도 마찬가지로 URL로 문제 ID값을 가져와서 useQuery로 캐싱된 데이터를 그대로 가 져와서 사용한다