[TIL] React Query (2)

·2023년 12월 12일
0

TIL

목록 보기
54/85
post-thumbnail

React-Query 란 ?

  • 리액트 쿼리는 서버 상태 관리를 쉽게 하도록 도와주는 라이브러리 이다.

"서버 상태 관리를 쉽게 한다" 란?
1. fetching : 서버에서 데이터 받아오기
2. caching : 서버에서 받아온 데이터를 따로 보관해서 동일한 데이터가 단 시간 내에 다시 필요할 시 서버 요청 없이 보관된 데이터 꺼내 쓰기
3. synchronizing : 서버 상의 데이터와 보관 중인 캐시 데이터(서버 상태) 를 동일하게 만들기
4. updating : 서버 데이터 변경 용이 (mutation & invalidateQueries)

Stale-while-revalidate (SWR 전략)

  • 신규 데이터가 도착하는 동안 일단 기존에 캐싱된 데이터를 사용하도록 하는 전략

⬆️ 클라이언트가 0~1초 사이에 다시 데이터를 요청하면, 서버 호출 없이 캐시 데이터를 바로 사용

⬆️ 클라이언드가 1~60초 사이에 다시 데이터 요청하면, 일단 캐시 데이터를 사용하고 서버에서 신규 데이터를 주면 그것으로 교체

캐시 데이터는 어디에 보관 ?

  • QueryClientProvider 는 React Context API 를 내부적으로 사용한다.
  • QueryClientProvider 의 자식으로 있는 모든 컴포넌트들은 캐시 데이터에 접근할 수 있습니다.
  • 페이지 컴포넌트 외부에 상태가 존재한다는 점에서 캐시 데이터는 전역 상태로 볼 수 있다.
// App.jsx
const queryClient = new QueryClinet();

const App = () => {
	return (
		<QueryClientProvider client={queryClient}>
			<Router />
		</QueryClientProvider>
	);
}

React Query VS Tanstack Query

  • Tanstack Query 란 ?
    : React Query의 v4 부터 라이브러리 명이 Tanstack Query로 변경되었다. 리액트 뿐만 아니라 Vue, Angular 등 다른 SPA 프레임 워크에도 적용할 계획인 것!
// "react-query": "^3.39.3"
yarn add react-query

// "@tanstack/react-query": "^4.29.19"
yarn add @tanstack/react-query
  • v4 부터는 쿼리 키를 반드시 배열 형태로 써줘야 한다.
useQuery("todos", getTodos); ❌ 에러 발생

useQuery(["todos"], getTodos); ✅ 정상 동작

React Query 의 Lifecycle

기본 설정의미
staleTime: 0useQuery 또는 useInfiniteQuery에 등록된 queryFn 을 통해 fetch 받아온 데이터는 항상 stale data 취급
refetchOnMount: trueuseQuery 또는 useInfiniteQuery 가 있는 컴포넌트가 마운트 시 stale data 를 refetch 자동 실행
refetchOnWindowFocus: true실행중인 브라우저 화면을 focus 할 때 마다 stale data를 refetch 자동 실행
refetchOnReconnect: trueNetwork 가 끊겼다가 재연결 되었을 때 stale data를 refetch 자동 실행
cacheTime: 5분 (1000 60 5 ms)useQuery 또는 useInfiniteQuery가 있는 컴포넌트가 언마운트 되었을 때 inactive query라 부르며, inactive 상태가 5분 경과 후 GC(가비지콜렉터)에 의해 cache data 삭제 처리
retry: 3useQuery 또는 useInfiniteQuery에 등록된 queryFn 이 API 서버에 요청을 보내서 실패하더라도 바로 에러를 띄우지 않고 총 3번까지 재요청을 자동으로 시도
  • StaleTime VS cacheTime
    • StaleTime : 얼마의 시간이 흐른 뒤에 stale 취급 할건지 (default 0)
    • cacheTime : inactive 된 이후로 메모리에 얼마만큼 있을건지
  • staleTime 과 stale/fresh 의 관계
    • staleTime > 0 이면, fresh data
    • staleTime = 0 이면, stale data
  • 하나의 쿼리 키(쿼리 인스턴스)마다 위와 같은 LifeCylce을 가진다.

isLoading VS isFetching

✅ isLoading : 새로운 캐시 데이터를 서버에서 받고 있는지 여부

  • 캐시 데이터가 있는 경우 isLoading은 false, isFetching은 true

✅ isFetching : 서버에서 데이터를 받고 있는지 여부

  • 쿼리 함수가 실행됐는지 안됐는지에만 관심

메인페이지와 상세페이지가 모두 useQuery(”todos”, getTodos) 를 가질 때, 메인페이지 → 상세페이지 순으로 이동할 때 메인페이지 재 마운트 시의 isLoading, isFetching 의 콘솔로그값은?

<메인>
isLoading true , isFetching true
getTodos 호출
isLoading false , isFetching false

<상세>
getTodos 호출
isLoading false , isFetching true
isLoading false , isFetching false

useQuery 실행 시 cacheTime > 0 인 것과 queryFn 실행 간의 관계

  • cacheTime > 0 인 것고 queryFn 실행은 상관 없다. staleTime과 관계가 있다.
  • cacheTime > 0 이면, 캐시 데이터가 존재하고, 이 경우 useQuery를 실행할 때 stale data 를 우선 받고 staleTime 이 0 이면 queryFn 을 실행한 리턴 값으로 리렌더링 하면서 바꿔준다.
  • cacheTime = 0 이 되면, 캐시 데이터가 삭제되기 때문에, 이 경우 useQuery로 data 호출 시 undefined 값을 우선 받고, queryFn을 실행한 리턴값으로 리렌더링하면서 바꿔준다.

useQuery에서 자주 사용하는 옵션들

enabled

useQuery(["todos"], getTodos, { enabled: true })
  • boolean type (true or false)
  • true인 경우에만 queryFn 실행
  • enabled 옵션이 없을 경우, 기본 값으로 true 생각하고 useQuery 자동 실행 됨.

적용 예제 (1) Disabling/Pausing Queries (이벤트 발생 시에만 수동 실행하고 싶을 때)

const { data, refetch } = useQuery(["todos"], getTodos, {
  enabled: false
});

return (
	<div>
    <button onClick={() => refetch()}>데이터 불러오기</button>
  </div>
);

적용 예제 (2) Dependent Queries (useQuery 2개 이상이며 실행순서 설정 필요할 때)

// Dependent Query 예제 (순차적 query 실행)
// Get the user
const { data: user } = useQuery({
  queryKey: ['user', email],
  queryFn: getUserByEmail,
})

const userId = user?.id

// Then get the user's projects
const {
  status,
  fetchStatus,
  data: projects,
} = useQuery({
  queryKey: ['projects', userId],
  queryFn: getProjectsByUser,
  // The query will not execute until the userId exists
  enabled: !!userId
})
// 여기서 !!userId 는 Boolean(userId)와 같습니다.

select

  • queryFn에 의해 리턴된 값을 변형시킨 후에 useQuery의 리턴 data로 넘겨준다.
  • 단, cache data는 queryFn에서 리턴받은 값 그대로 이다.
import { useQuery } from 'react-query'

function User() {
  const { data } = useQuery(['user'], fetchUser, {
    select: (user) => user.username,
  })
  return <div>Username: {data}</div>
}
profile
느리더라도 조금씩, 꾸준히

0개의 댓글