2022-03-20 TIL

Fact

  • 리액트 쿼리 공부

Findings

React Query는 서버 상태(server state)를 관리하는 라이브러리다. 서버 상태란

  • 원격에 위치한 공간에 저장되며 앱이 소유하거나 제어하지 않는다.
  • 데이터를 가져오고 업데이트 하기 위해선 비동기 API가 필요하다.
  • 다른 사람과 함께 사용하며, 내가 모르는 사이에 업데이트될 수 있다.
  • 앱에서 사용하는 데이터가 “유효 기간이 지난” 상태가 될 가능성을 가진다.

예를 들어 쇼핑몰의 상품 목록, 게시판의 댓글, 배달앱의 주문 진행 상황 등은 모두 위와 같은 특성을 가지고 있다. 그렇기에 다음과 같은 작업에 대한 필요가 생긴다.

  • 캐싱
  • 만료된 데이터를 백그라운드에서 제거하기
  • 데이터가 언제 만료되는지 알고 있기
  • 만료된 데이터는 가능한 빨리 업데이트하기
  • 페이지네이션, 레이지 로딩 데이터의 성능 최적화
  • 서버 상태의 메모리 관리 및 가비지 콜렉션
  • 쿼리 결과의 구조 공유를 통한 메모리제이션

이러한 기능들이 없어도 앱을 구현할 수 있다. 하지만 높은 품질의 앱을 위해서는 필요한 작업이라 할 수 있다. React Query는 위와 같은 기능을 사용할 수 있도록 도와준다.

React Query를 사용한다면 서버 데이터 처리 방식을 바꿔야 한다. React에서는 보통 redux, mobx같은 상태 관리 라이브러리를 사용하며, 그것으로 서버 상태를 관리하는 방식이 일반적이다. Redux를 사용하고 있다면, redux-thunk, redux-observable, redux-saga 등의 미들웨얼르 사용해 서버 데이터 요청 액션이 들어오면 API를 호출하여 redux 상태를 업데이트하는 방식을 사용한다. 하지만 React Query는 기본적으로 함수형 컴포넌트 안에서 훅 형태로 사용하며 굳이 서버 상탤르 다른 장소에 저장할 필요가 없다.

필요에 따라 서버 데이터를 현재 컴포넌트에서 멀리 떨어진 컴포넌트 트리에 전달할 필요가 생길 수도 있다. 하지만 서버 상태는 그 데이터를 가져온 컴포넌트와 1~2단계 아래의 하위 컴포넌트(ex. 목록의 아이템 컴포넌트)에서 사용하는 경우가 대부분이다. 즉, 서버 데이터 처리와 관련된 redux 액션, 리듀서, 미들웨어 코드를 작성할 필요가 없어진다. Redux는 훌륭한 상태 관리 기능을 제공하지만, 동시에 많은 양의 boilerplate 코드라는 피로감도 제공하고 있기에 주목할 필요가 있다.

하지만 상태 관리 라이브러리를 사용해서 서버 데이터를 제어하는 쪽을 더 선호한다면 React Query는 도입하지 말거나 앱에서 꼭 필요한 부분에만 사용하는 편이 좋을 것이다.

캐싱 & 리프레쉬

채팅 앱처럼 소켓 통신을 사용한다면 서버 상태가 즉시 업데이트 되겠지만 그렇지 않다면 주기적으로 업데이트해주는 기능을 직접 구현해야한다. React Query는 useQuery 훅의 파라미터를 통해 API 데이터의 만료 시간, 리프레쉬 간격, 데이터를 캐시에서 유지할 기간, 브라우저 포커스시 데이터 리프레쉬 여부, 성공 or 에러 콜백 등 다양한 기능을 제어할 수 있다.

예를 들어 앱 안에 게시판이 있다고 가정하면. 다음과 같은 시나리오가 가능하다.

  • 게시글 필터에서 사용하는 옵션은 서버에서 변경될 가능성이 낮으므로 만료 시간을 무한으로 설정하여 API 추가 호출을 방지할 수 있다.
  • 게시글 목록의 만료 시간을 1분으로 설정하여 유저가 페이지 번호를 1에서 2로 반복해서 바꾸는 등의 행동을 취하더라도 API 중복 호출을 방지할 수 있다.
  • 게시글 목록의 만료 시간이 1분으로 설정되어 있는데 어떤 사용자는 게시글을 그 시간 안에 작성하거나 수정할 수도 있다. 그래서 게시글 작성 후에는 캐시를 강제로 무효화하여 목록을 새로고침한다.
  • 사용자가 게시글의 제목을 수정한 후 목록을 돌아갔을 때 API 호출을 통해 게시글 목록을 서버에서 다시 가져온 후에야 수정 사항이 반영되었음을 확인해줄 수 있다. 하지만 React Query에서는 수정 성공시 캐시되어 있는 게시글 제목을 임시로 변경하여 사용자에게 서버에 다시 요청한 게시글 목록의 응답이 즉시 온 것처럼 보이게 만들 수 있다.
  • 게시글 수정 후 목록 새로고침에 딜레이가 전혀 없는 듯한 사용자 경험을 제공할 수 있다.
  • 실제 API 호출 및 데이터 업데이트는 백그라운드에서 진행되며 에러 발생시 원래 데이터로 복구시킬 수 있다.
  • Optimistic update 참조
  • 브라우저의 다른 탭을 보다가 다시 열었을 때 게시글 목록을 자동으로 불러오게 할 수 있다.

캐싱 관련 기능은 처음 언급한대로 구현되어 있지 않아도 앱 사용하는 데는 문제가 없다. 하지만 클라이언트에서 사용하는 서버 데이터의 종류와 양이 늘어나고 서버에서 관리하고 있는 데이터의 양도 늘어난다면 양쪽 모두의 작업 처리량을 줄일 필요가 자연스럽게 생긴다. 또 더 좋은 사용자 경험을 구현하는데도 도움을 준다.

React Query 사용 방법

React Query를 통해 관리하는 쿼리 데이터는 라이프사이클에 따라 fetching, fresh, stale, inactive, delete 상태를 가진다.

  • fetching - 요청 중인 쿼리
  • fresh - 만료되지 않는 쿼리. 컴포넌트가 마운트, 업데이트되어도 데이터를 다시 요청하지 않는다.
  • stale - 만료된 쿼리. 컴포넌트가 마운트, 업데이트되면 데이터를 다시 요청한다.
  • inactive - 사용하지 않는 쿼리. 일정 시간이 지나면 가비지 컬렉터가 캐시에서 제거한다.
  • delete - 가비지 컬렉터에 의해 캐시에서 제거된 쿼리

important defaults

다음은 React Query에서 제공하는 API의 기본이 되는 설정이다.