React.js

[React] React-Query 사용하기

Chunho 2022. 1. 20. 00:05

React-Query는 기존에 프로그래머가 직접 작성해야 했던 비동기 http 통신 로직을 쉽게 다룰 수 있게 해주는 라이브러리이다. 

데이터를 항상 최신 상태로 유지해주며, loading, error, success 등 일렬의 컨트롤을 쉽게 할 수 있다.

yarn add react-query 명령어를 사용하여 라이브러리를 설치해준 후 

package.json 파일에서 정상적으로 설치가 된 것을 확인해준다.

이후 Context로 하위 컴포넌트를 감싼 후 queryClient를 내려보내 준다. 

queryClient는 비동기 요청을 알아서 처리하게 해주는 Background가 된다. 

 

쿼리는 4가지의 상태를 가진다. 

1. fresh: 새롭게 추가된 쿼리 인스턴스이며, active 상태의 시작이다. staleTimedl 0이기 때문에 아무런 설정을 해주지 않으면 호출이 끝나고 바로 stale상태로 변한다. 

2.fetching: 요청을 수행하는 중인 쿼리이다.

3: stale: 인스턴스가 존재하지만 이미 패칭이 완료된 쿼리이다. 특정 쿼리가 stale된 상태에서 같은 쿼리 마운트를 시도한다면 캐싱된 데이터를 반환하면서 리패칭을 시도한다. 

4. inactive: active 인스턴스가 하나도 없는 쿼리이다. inactive된 이후에도 cacheTime동안 캐시된 데이터가 유지되며 cacheTime이 지나면 GC된다.

  • *어떻게 inactive가 되는가? : pagenation 관련한 예제를 보니, 페이지네이션을 할 때마다 컴포넌트가 재랜더링 되면서 새로운 쿼리가 만들어지고, 저번 랜더링에서 호출했던 쿼리들은 inactive된다. 렌더링간에 다시 호출되지 않고 언마운트되는 쿼리들은 inactive가 되는 듯 보인다.

출처:https://maxkim-j.github.io/posts/react-query-preview

 

React-Query 살펴보기

React의 Server State 관리 라이브러리 React Query를 살펴봅니다.

maxkim-j.github.io

위와 같이 쿼리문을 작성 해보았다.

  • 쿼리는 server state를 요청하는 프로미스를 리턴하는 함수와 함께 unique key로 맵핑된다.
  • 쿼리는 콜백 함수의 요청이 프로미스를 리턴한다면 일단 잘 작동한다. 하지만 서버의 데이터를 바꿀 수 있는 요청이라면 mutation 쓰는게 더 추천된다.(이유는 아래 mutation 부분에서 다시 설명)
  • useQuery훅의 인자로 2개가 들어감 - 쿼리의 unique한 key, 프로미스를 리턴하는 함수(이 함수는 반드시 resolve Promise를 리턴하거나 에러를 throw해야 한다.)
  • unique key : 한 번 fresh가 되었다면 계속 추적이 가능하다. 리패칭, 캐싱, 공유 등을 할때 참조되는 값. 주로 배열을 사용하고, 배열의 요소로 쿼리의 이름을 나타내는 문자열과 프로미스를 리턴하는 함수의 인자로 쓰이는 값을 넣는다.
  • useQuery 반환값 : 객체, 요청의 상태를 나타내는 몇가지 프로퍼티, 요청의 결과나 에러값을 갖는 프로퍼티도 포함함
    • isLoading, isError, isSuccess, isIdle, status
    • error, data, isFetching ⇒ 런타임간 무조건 요청이 한 번 이상 발생했다면 값이 존재한다.
  • 쿼리 요청 함수의 상태를 표현하는 status값은 4가지다. status 프로퍼티에서는 문자열로, 상태 이름 앞에 is를 붙인 프로퍼티에서는 불리언으로 해당 상태인지 아닌지를 평가 가능하다.
    • idle : 쿼리 data가 하나도 없고 비었을 때. {enabled : false} 상태로 쿼리가 호출되었을 때 이 상태로 시작된다.
    • loading : 말그대로 로딩중일 때
    • error : 말그대로 에러 발생했을 때
    • success : 말그대로 요청 성공했을 때
  • 주요 쿼리 옵션
    • enabled : 이걸 True로 설정하면 자동으로 쿼리의 요청 함수가 호출되는 일이 없다
    • keepPreviousData : success와 loading 사이 널뛰기 방지
    • placeholderData : mock 데이터 설정도 가능. 얘는 근데 캐싱이 안됨
    • initialData : 초기값 설정
    • retry
    • 쿼리에 여러가지 옵션 설정을 통해 입맛대로 데이터를 관리할 수 있다

1초의 Loading... 문구 뒤에 데이터가 찍히는 것을 확인할 수 있었다.

  • 다음 4가지 경우에 리패칭이 일어난다
    1. 런타임에 stale인 특정 쿼리 인스턴스가 다시 만들어졌을 때
    2. window가 다시 포커스가 되었을때(옵션으로 끄고 키는게 가능)
    3. 네트워크가 다시 연결되었을 때(옵션으로 끄고 키는게 가능)
    4. refetch interval이 있을때 : 요청 실패한 쿼리는 디폴트로 3번 더 백그라운드단에서 요청하며, retry, retryDelay 옵션으로 간격과 횟수를 커스텀 가능하다.

잘못 된 API주소로 요청을 했을 때 3번 더 요청을 했으며, 다른 브라우저를 클릭하여 포커스를 옮긴 후 실행중인 리액트 앱을 다시 클릭해서 포커스가 됐을 때 리패칭이 일어났다.

 

쿼리 키를 배열로 준 후 파라미터를 주어 id값 등 구분자로 이용할 수도 있다.

 

 

useMutation

useQuery를 사용하면, 최상위에서 호출해야된다는 훅의 규칙에 위배되기 때문에
create, update, delete 등과 같이 이벤트 핸들러를 사용하여 server state에 사이드 이펙트를 일으키는 경우에는 mutation을 사용하는것이 좋다!!!!!( 이 때 쿼리무효화 invalidation 필수 ).

위와 같이 mutaion hook을 짜주었다.

버튼을 클릭 할 시에 새로운 데이터를 POST한다. 

 

데이터가 잘 추가된 것을 확인할 수 있었다. console로 useMutation의 onSeccess함수가 받는 매개변수도 출력해보았다. variables는 전송한 객체이며, context는 onMutate에서 return한 값이다. 이 때 쿼리무효화를 해주지 않으면 서버의 데이터가 변경 된 후에 리패칭이 되지 않아 윈도우에 다시 포커스가 됐을 때 useQuery의 규칙에 따라 리패칭이 되었다. 

 

쿼리 무효화를 명시해주면 쿼리키를 참조하여 자동으로 리패칭을 시도하고 추가된 데이터가 view에 나타난다.

 

+ useMutation의 경우, CUD에 해당하는 API 콜 후, 서버의 response를 data에서 받아올 수 없다.  성공/실패 여부는 알 수 있다!