티스토리 뷰

front-end/react

React query

kmj24 2023. 5. 3. 21:48
  • React Application에서 서버 상태 관리(Caching, Continous Synchronization, etc…)의 도움을 주는 라이브러리이다.
  • api요청을 보낼 때, React의 Local state와 Server state를 동기화하게 되는데 이때 편의성을 준다.

Client state vs Server state

Client state

  • 클라이언트 소유
  • 클라이언트에서 제약없는 제어가 가능함
  • Client내 UI/UX 흐름 또는 사용자 인터렉션에 따라 변할 수 있음
  • Client내에서 최신 상태로 관리됨

Server state

  • 서버의 상태, 클라이언트 입장에서는 원격의 공간에서 제어되는 상태
  • Fetching / Updating에 비동기 API가 필요
  • 다른 클라이언트들과 공유되며, 클라이언트가 모르는 사이 변경될 수 있음
  • 신경쓰지 않을 경우, out of date가 될 잠재적인 가능성이 있음

단순 API request

  • 단순한 요청, XMLHttpRequest, fetch, axios 등을 실행한 요청
    • React 컴포넌트 내에서 서버 상태를 동기화 하게 되며 코드가 장황해짐(state drilling, loading 등)
  • 전역 상태 관리 시스템을 이용한 API
    • 서버 상태를 React 컴포넌트 외부에서 관리
    • redux를 사용할 경우 redux 특징인 작성되는 코드가 길어짐
  • React-query
    • 상대적으로 간결한 문법을 제공
    • 각종 옵션으로 편의성을 제공(interval polling, Garbage collection 설정 등)
    • Caching으로 빠른 성능 제공
    • 불필요한 다중 요청 방지 제공

react-query의 컨셉

  • RFC 5861 (Request for Comments - 인터넷 개발에 필요한 기술, 결과, 절차 등 메모해놓은 문서)
    • HTTP Cache-Control Extensions for Stale Content
    • stale-while-revalidate
      • 백그라운드에서 stale response(오래된 응답)를 revalidate(refetch)하는 동안 캐시가 가진 stale response(이전 응답, 오래된 응답)를 반환
    • Cache-Control header
      Cache-Control: max-age=600, stale-while-revalidate=30
      • 600s가 넘어갈 경우 해당 데이터는 stale(오래 되었다)판단
      • 600s ~ 30s refetch한다.
      • Latency가 숨겨지는 이점이 있다.
  • 이 컨셉을 메모리 캐시에 적용 시도
    • 결과물 : react-query, swr, …
    • react-query에서,,
      • cacheTime : 데이터가 메모리에 얼마 동안 존재할 것인가(해당 시간 이후 GC가 제거, default 5분)
      • staleTime : 얼마의 시간이 흐른 후 데이터를 stale 취급할 것인가 (default 0)
    • react-query stale 옵션
      • refetchOnMount : mount시점에 데이터를 stale 취급
      • refetchOnWindowFocus : window의 focus 시점에 데이터를 stale 취급
      • refetchOnReconnect : reconnect 시점에 데이터를 stale 취급
      • stale이라 판단되면 refetch (default : true)

Query life-cycle

  1. query 인스턴스가 mount됨
  2. stale time이 0보다 크다면 fresh상태
  3. stale time만료 시 stale 상태가 됨
  4. 스크린에서 사용되는 동안 stale 상태는 지속된다.
  5. 스크린에서 사용되지 않는다면 query는 inactive 상태가 됨
  6. cache time이 만료되기 전까지 메모리 상에서 존재함
  7. cache time이 만료될 경우 GC가 제거
  8. inactive 상태였다가 다시 스크린에 나타나야 될 경우 refetchOnMount 상태가 되며, refetch 실행

react-query default config

  • Queries에서 Cached data는 언제나 stale 취급
  • 각 시점에서 data가 stale이라면 항상 refetch 발생
  • Inactive query들은 5분 뒤 GC가 제거
  • Query 실패 시 최대 3번 retry 발생

react-query 데이터

  • stale time은 30s로 설정
  • 컴포넌트A에서 api-1을 호출
  • 10초뒤 컴포넌트B에서 api-1을 호출
  • 같은 api-1을 호출하지만 컴포넌트B에서 api-1호출은 실행되지 않는다.
  • Context API를 활용한 전역상태로 관리되는 데이터
    • QueryClient 내부적으로 Context API를 사용함

react-query 사용 방법

  • Application에서 사용할 부분에 QueryClientProvider를 설정한다.
import { QueryCLient, QueryClientProvider } from 'react-query';

const queryClient = new QueryClient();

function App() {
	return <QueryClientProvider client={queryClient}>...</QueryClientProvider>
}

useQuery

  • 데이터를 읽을 때 사용

Query Key

import { useQuery } from 'react-query';

function App() {
	// useQuery(query key, ...);
	const info = useQuery(**query key**, fetcher);

	//...
}
  • react query는 query key에 따라 캐싱을 관리한다.
  • 데이터는 query key와 매핑된다.
  • 데이터 타입은 string, Array이 될 수 있으며, react-query v4(beta)부터는 array 타입만 허용한다고 한다.
  • query key는 해싱 되며, 아래의 키는 모두 같은 것으로 간주된다.
useQuery(['todos', { status, page }], ...)
useQuery(['todos', { page, status }], ...)
useQuery(['todos', { page, status, other: undefined }], ...)
  • 하지만 아래의 형태는 같은것으로 간주되지 않는다. (배열의 순서가 중요)
useQuery(['todos', status, page], ...)
useQuery(['todos', page, status], ...)
useQuery(['todos', undefined, page, status], ...)

Query function

import { useQuery } from 'react-query';

function App() {
	// useQuery(query key, query function);
	const info = useQuery(query key, **fetcher**);

	//...
}
  • promise를 반환하는 함수
  • api fetch함수가 들어간다.

Query Options

import { useQuery } from 'react-query';

function App() {
	// useQuery(query key, query function, query option);
	const info = useQuery(query key, fetcher, **option**);

	//...
}
  • useQuery를 사용할 때 옵션 설정
  • onSuccess, onError, onSettled
    • 데이터 타입(순서대로) : (data: TData) ⇒ void, (error: TError) ⇒ void, (data?: TData, error?: TError) ⇒ void
    • query fetching 성공 실패 완료 시 실행할 side effect 정의
  • enabled
    • 데이터 타입 : boolean
    • 자동으로 query를 실행 할지 여부
  • retry
    • 데이터 타입 : boolean | number | (failureCount: number, error: TError) ⇒ boolean
    • 실패한 쿼리 재시도 옵션
    • true설정 시 무한 재시도, false설정 시 재시도x
    • default = 3번
  • select
    • 데이터 타입 : (data: TData) => unknown
    • 성공 시 가져온 데이터 가공
  • keepPreviousData
    • 데이터 타입 : boolean
    • 새롭게 fetching시 이전 데이터 유지 여부
  • refetchInterval
    • 데이터 타입 : number | false | ((data: TData | undefined, query: Query) => number | false)
    • polling 사용 여부
    • number타입 설정 시 해당 쿼리가 ms 단위로 refetch
    • function설정시 최신 데이터로 함수가 실행, 빈도를 계산하는 쿼리 실행
    • default = false
  • staleTime (number | Infinity)
    • 데이터가 fresh상태로 유지되는 시간 (fresh상태일 경우 쿼리가 다시 마운트 되어도 fetch는 실행되지 않음)
    • 해당 시간 초과 시 stale 상태로 변경됨
    • default = 0
  • etc..

useMutation

  • 데이터를 업데이트 할때 사용(post, put, delete)
  • useQuery는 즉시 실행되지만, useMutation은 즉시 실행되지 않는다.
  • useQuery는 상태를 공유하지만, useMutation은 그렇지 않다
    • useQuery는 다른 컴포넌트에서 동일한 useQuery를 여러번 호출할 수 있으며, 캐시된 결과를 동일하게 반환하지만, useMutation에는 그런 기능이 없다.
const { data, error, isError, isLoading, mutate, mutateAsync, reset ... } = 
	useMutation(mutationFunction, options);
  • 반환 값
    • mutate
      • mutation을 실행하는 함수
    • mutateAsync
      • mutate와 비슷하지만 promise를 반환
    • reset
      • mutation내부 상태 clear
    • etc…
  • options
    • onMutate
      • 데이터 타입 : (variables) ⇒ Promise<TContext | void> | TContext void
      • 본격적인 Mutation동작 전에 먼저 동작하는 함수
      • Optimistic update 적용시 유용함
      • Optimistic update - 낙관적 업데이트 - UI에서 어차피 업데이트 할 것이란 가정으로 UI를 업데이트 후 서버를 통한 검증 - 실패한다면 롤백
    • onMutateAsync
      • onMutate의 비동기
    • etc…

Query Invalidation

  • queryClient를 통해 invalidate 메서드 호출
// Invalidate every query in the cache
queryClient.invalidateQueries()

// Invalidate every query with a key that starts with 'todos'
queryClient.invalidateQueries('todos')
  • 해당 key를 가진 query는 stale 취급
  • 현재 rendering되고 있는 query는 백그라운드에서 refetch된다.

query 파일 분리

  • 컴포넌트에서 직접 useQuery를 호출한다면 관리의 어려움이 있을 수 있다.
  • query fetching역할의 파일을 따로 분리하는것 권장한다.
  • 배민 주문시스템의 웹뷰에서 데이터 패칭을 할 때 도메인 별로 묶어서 관리한다고 한다.

query 상태

  • fetching : 데이터 요청 상태
  • fresh : 데이터가 만료되지 않은 상태
  • stale : 데이터가 만료된 상태
  • inactive : 사용하지 않는 상태
  • delete : GC에 의하여 Cache에서 제거된 상태

react-query 사용상 장점

  • 서버 상태 관리 용이 (redux, mobx보다 직관적인 API 호출, Caching 으로 빠른 성능 지원)
  • API 처리에 대한 각종 인터페이스, 옵션 제공
  • Client store는 클라이언트의 상태만 남아서 store답게 사용됨
  • Cache전략 사용 시 효율적

'front-end > react' 카테고리의 다른 글

react-native로 간단한 Todo 앱 구현하기  (0) 2024.06.08
react-native 설치해보기  (0) 2024.06.08
Redux 구현  (0) 2023.05.03
가상 돔, Virtual DOM  (0) 2023.05.03
React useState, useEffect Mechanism(with. closure)  (0) 2023.05.03
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/06   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
글 보관함