[React Query] 1. Query 생성하기 / Loading, Error 처리하기

hzn·2023년 3월 7일
0

React Query

목록 보기
3/4
post-thumbnail

[Udemy] React Query로 서버 상태 관리하기


참고 : Client State와 Server State

Client State

  • 웹 브라우저 세션과 관련된 데이터
  • ex) 언어 선택, 테마 선택

Server State

  • 서버에 저장된 데이터. 클라이언트에 표시하기 위해 필요
  • ex) 블로그 게시물 데이터

1. React Query

  • Server State(서버 상태)를 관리하는 리액트 라이브러리

  • 서버 데이터의 캐시를 관리 (해당 캐시의 데이터를 설정한 바에 따라 유지 관리)

  • 서버 데이터가 필요할 때, fetch, axios 등을 이용해 바로 서버에 요청하지 않고, 일단 React Query cache를 요청한다.

  • 서버의 새 데이터로 캐시를 업데이트하는 시기는 사용자가 지정해줘야 한다.

캐시 업데이트 시점을 지정해주는 여러 방법들..

1) invalidate : 데이터를 무효화한다 refetch가 이루어지도록 한다.
2) refetch가 일어나는 조건을 지정한다 (e.g. window focus 등)
3) staleTime을 지정한다.


6. useQuery로 쿼리 생성하기

1) queryClient 생성, QueryClientProvider 적용

App.jsx

import { Posts } from './Posts';
import './App.css';
import { QueryClient, QueryClientProvider } from 'react-query'; // 불러오기

const queryClient = new QueryClient(); // queryClient 생성

function App() {
  return (
    <QueryClientProvider client={queryClient}> // QueryClientProvider 적용
      <div className="App">
        <h1>Blog Posts</h1>
        <Posts />
      </div>
      <ReactQueryDevtools /> // 넣기
    </QueryClientProvider>
  );
}

export default App;

2) useQuery로 쿼리 생성

Post.jsx

import { useState } from 'react';
import { useQuery } from 'react-query';

import { PostDetail } from './PostDetail';
const maxPostPage = 10;

async function fetchPosts() { // 쿼리 함수
  const response = await fetch(
    'https://jsonplaceholder.typicode.com/posts?_limit=10&_page=0'
  );
  return response.json();
}

export function Posts() {
  const [currentPage, setCurrentPage] = useState(0);
  const [selectedPost, setSelectedPost] = useState(null);

  // replace with useQuery
  const { data } = useQuery('posts', fetchPosts ); // useQuery로 쿼리 생성

  return (
    <>
      <ul>
        {data.map((post) => ( // 받아온 data 사용
          <li
...

{JSON} Placeholder

  • CRUD 가능한 무료 가상 REST API 서버
  • 설치 필요 X. 호출만 하면 된다.

7. 로딩, 에러 처리하기

  • useQuery를 이용해 (구조분해할당으로) data 외에 isLoading, isError, error 등을 받아올 수 있다.
  • isLoading, isError는 boolean 값.

Post.jsx

...
export function Posts() {
  const { data, isError, error, isLoading } = useQuery('posts', fetchPosts);
  if (isLoading) return <h3>Loading...</h3>; // Loading 처리
  if (isError) // Error처리
    return (
      <>
        <h3>Oops, something went wrong!</h3>
        <p>{error.toString()}</p> // error메시지 보여주기
      </>
    );
  return (
    <>
      <ul>
        {data.map((post) => (
          <li
...

isFetching vs. isLoading

isFetching

  • 데이터를 fetch하는 비동기 쿼리 (함수)가 아직 처리중일 때.
  • 캐싱 데이터가 있어서 백그라운드에서 fetch 되더라도 true

isLoading

  • isFetching + 캐시된 데이터가 없음 (= 이 쿼리를 만든 적이 없음. 처음 만드는 것)

8. React Query Devtools

App.jsx

...
import { QueryClient, QueryClientProvider } from 'react-query';
import { ReactQueryDevtools } from 'react-query/devtools'; // 불러오기

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <div className="App">
        <h1>Blog Posts</h1>
        <Posts />
      </div>
      <ReactQueryDevtools /> // 넣기
    </QueryClientProvider>
  );
}

export default App;


9. staleTime vs. cacheTime

React Query의 라이프 사이클

  1. A 쿼리 인스턴스가 mount 됨
  2. 네트워크에서 데이터 fetch 하고 A라는 query key로 캐싱함
  3. 이 데이터는 fresh 상태에서 staleTime(기본값 0) 이후 stale 상태로 변경됨
  4. A 쿼리 인스턴스가 unmount 됨 = 데이터가 inactive 상태로 변경됨
  5. 캐시는 cacheTime(기본값 5분) 만큼 유지되다가 가비지 콜렉터로 수집됨
  6. 만일 cacheTime이 지나기 전에 A 쿼리 인스턴스가 새롭게 mount되면, fetch가 실행되고 fresh한 값을 가져오는 동안 캐시 데이터를 보여줌

staleTime

  • 데이터가 fresh -> stale 상태로 변경되는데 걸리는 시간
  • 기본값은 0ms
  • refetch는 데이터가 stale 상태일 경우에만 실행됨.
    (fresh 상태일 때는 refetch 일어나지 않음)

    😀 refetchOnMount 설정값이 true(기본값)라면 mount될 때 refetch가 일어나지만...
    만일 staleTime을 길게 설정해서 아직 fresh 상태인 채로 unmount 됐다가 다시 mount 될 때까지 staleTime이 끝나지 않았다면?
    👉🏽 refetch 되지 않는다! (refetch는 stale 상태일 경우에만 일어난다)

cacheTime

  • Cache(캐시) : 나중에 다시 사용할 수도 있는 데이터
  • 데이터가 inactive 되고 나서 캐싱된 상태로 남아있는 시간
  • 기본값은 5분
  • 해당 쿼리에 대한useQuery가 마지막으로 실행된 시점으로부터 계산 (...?)
  • 데이터가 stale 상태가 되어서 쿼리 인스턴스가 unmount 되면 데이터는 inactive 상태로 변경되며, 이후 캐시는 cacheTime 만큼 유지된다.
    (inactive된 시점을 기준으로 cachTime 계산이 시작된다)
  • cacheTime이 지나면 가비지 콜렉터로 수집된다. (이후에는 클라이언트에서 데이터를 보여줄 수 없다. 빈 화면으로 보여짐)
  • cacheTime이 지나기 전에 쿼리 인스턴스가 다시 마운트 되면, 데이터를 fetch하는 동안 캐시 데이터를 보여준다.

👉🏽 보통은 빈 화면을 보여주는 것보다 약간 오래된 데이터(stale 된 후 캐싱 상태의 데이터)를 표시하는 것이 낫지만
👉🏽 조금이라도 오래된 데이터를 보여주면 안되는 경우에는 cacheTime을 0으로 설정해준다.

staleTime, cacheTime 지정하기

  • useQeury의 3번째 인자(options)로 지정할 수 있다.
  • options는 객체 형태로 넣어준다.

Post.jsx

...
const { data, isError, error, isLoading } = useQuery('posts', fetchPosts, {
    staleTime: 2000,
    cacheTime: 1500000
  });

참고

[react-query를 이해하는 몇가지 지식과 질문들]

  • refetching을 왜 하는가? => 지금 가지고 있는 정보가 fresh하지 않고 stale하니까

  • refetching 조건을 만족해도 fresh하다면 refetching하지 않는가? => 그렇다.

  • staleTime이 0이라면 어떻게 되는가? => 곧바로 stale이 되므로 refetching이 요구되는 상황이 오면 무조건 refetching하게 된다.

  • 언제 데이터가 cache되는가? => query를 보내고 데이터를 받아오자마자 cache된다. 그러나 cacheTime은 이 때 발동하지 않는다.

  • 그렇다면 cacheTime은 언제부터 시작인가? => unmount된 시점부터. 즉, inactive된 시점부터 시작한다.

  • cacheTime이 지나기 전에 다시 쿼리가 발동되면 어떻게 되는가? => cache된 값을 사용하고 background에서 다시 fetching된다.

  • cacheTime이 지나면 어떻게 되는가? => 메모리에 존재하는 데이터가 GC에 의해 삭제. 따라서 다시 active되면 hard loading한다.

  • cacheTime이 0이라면 어떻게 되는가? => 매번 GC 당하므로 매번 hard loading을 하게 된다.

0개의 댓글