React Query 사용 예제(2)

김재한·2023년 6월 20일
0

React 기초

목록 보기
8/9

1. Query State

기본적으로 쿼리들은 4개의 상태를 가지며, useQuery가 반환하는 객체의 프로퍼티로 상태를 확인할 수 있다.

  • Fresh
    새롭게 추가된 쿼리 인스턴스로 active 상태의 시작 상태이다. staleTime 동안 fresh 상태로 유지되는데, 이 동안에 쿼리가 다시 마운트 되면 데이터 패칭이 발생하지 않고 기존의 값을 반환한다.
  • Fetching
    데이터 패칭이 진행중인 상태이다.
  • Stale
    데이터 패칭이 완료되고 Not Fresh한 상태이다. 이 상태에서 쿼리가 마운트 되면 캐싱된 데이터를 반환하면서 리패칭이 이루어진다.
  • Inactive
    active 인스턴스가 하나도 없는 쿼리이다. inactive된 이후에도 cacheTime 동안 캐시 데이터가 유지되지만 이후에는 Garbage Collection 된다.

[ 데이터 리패칭이 일어나는 경우 ]

  • stale인 특정 쿼리 인스턴스가 다시 만들어졌을 때
  • Window에 다시 포커스가 되었을 때 (쿼리 옵션)
  • 네트워크가 다시 연결되었을 때 (쿼리 옵션)
  • reFetch interval이 있을 때
    요청 실패한 쿼리는 기본적으로 3번 더 요청하며, 이는 retry, retryDelay 옵션으로 커스텀이 가능하다.

2. useQuries

여러 개의 쿼리를 다룰 때 사용한다. useQuery를 여러 번 사용해도 동작하지만 useQuries를 사용하자

[예시]

const getPost = async (query) => {
  // useQuery의 queryKey 사용
  const { data } = await axios.get(
    `http://localhost:5000/posts/${query.queryKey[1]}`
  );
  return data;
};

const Parallel = () => {
  // useQuery(["post", 1], getPost);
  // useQuery(["post", 2], getPost);
  // useQuery(["post", 3], getPost);

  useQueries([
    { queryKey: ["post", 1], queryFn: getPost },
    { queryKey: ["post", 2], queryFn: getPost },
    { queryKey: ["post", 3], queryFn: getPost },
  ]);

  return <div>Parallel Queries Page</div>;
};

[결과]

3. Dependent Quries

기본적으로 쿼리들은 순서가 보장되지 않는 비동기 방식으로 동작한다. 다른 쿼리에 의존해 순서가 보장되는 동기 방식으로 실행하려면 enabled 옵션을 사용하면 된다.

const getPost = async ({queryKey}) => {
  const { data } = await axios.get(
    `http://localhost:5000/posts/${queryKey[1]}`
  );
  return data;
};

const getUser = async ({queryKey}) => {
  const { data } = await axios.get(
    `http://localhost:5000/users/${queryKey[1]}`
  );
  return data;
};


const DependentQueriesPage = () => {
  const { data: user } = useQuery(["user", "jae_han"], getUser);
  const { data: post } = useQuery(["post", user?.postId], getPost, {
    enabled: !!user?.postId,
  });

  console.log({ user });
  console.log({ post });

  return <div>Dependent Queries Page</div>;
};

[결과]
1. getUser 쿼리가 먼저 실행된다.
2. user 객체에 postId가 있는 경우에만 getPost 쿼리가 실행된다.
3. 이처럼 순서를 보장해 동기적으로 요청을 처리할 수 있다.

4. 캐싱 & 리패칭

React Query는 기본적으로 5분동안 query key를 식별자로 가지면서 각 데이터들을 캐싱해 놓는다.
캐싱된 데이터를 사용함으로써 사용자 경험을 높일 수 있다.

[예시]
상세 페이지 이동 시 보여지는 데이터를 전체 조회에서 캐싱된 데이터를 사용한다.

//index.js
const getPosts = async () => {
  const { data } = await axios.get("http://localhost:5000/posts");
  return data;
};
export default function Home() {

  const {
    data: posts,
    isLoading,
  } = useQuery("posts", getPosts);

  return (
    <>
      <div>
        {isLoading ? (
          <div>Loading...</div>
        ) : (
          posts?.map((post) => (
            <Fragment key={post.id}>
              <br />
              <Link href={`/post/${post.id}`}>
                <a>
                  <div>id: {post.id}</div>
                  <div>제목: {post.title}</div>
                  <div>작성자: {post.author}</div>
                  <div>내용: {post.description.slice(0, 100)}...</div>
                </a>
              </Link>
              <br />
              <hr />
            </Fragment>
          ))
        )}
      </div>
    </>
  )
}

메인 화면에서 useQuery("posts", getPosts) 를 통해 게시물 목록을 조회하고 5분동안 데이터를 캐싱시킨다.

// [id].js

const getPost = async (query) => {
  const { data } = await axios.get(
    `http://localhost:5000/posts/${query.queryKey[1]}`
  );
  return data;
};

const PostPage = () => {
  const router = useRouter();
  const { id: postId } = router.query;

  const queryClient = useQueryClient();

  const { data: post, isLoading } = useQuery(["post", postId], getPost ,
      {
    
        initialData: () => {
          // 캐시 데이터로 초기화
          const posts = queryClient.getQueryData("posts");

          const post = postId ? posts?.find((post) => post.id === +postId) : null;

          if (!post) {
            return undefined;
          }

          return post;
        },
      }
  );

  return (
    <div>
      {isLoading ? (
        <div>Loading...</div>
      ) : post ? (
        <>
          <div>id: {post.id}</div>
          <div>제목: {post.title}</div>
          <div>작성자: {post.author}</div>
          <div>내용: {post.description}</div>
        </>
      ) : null}
    </div>
  );
};

[결과]

  • getQueryData를 통해 'posts'라는 query key의 데이터로 필터링해 초기화 했기 때문에 Loading... 문구가 화면에 나타나지 않는다.
  • 초기값을 셋팅해 Loading... 이 보여지지 않을 뿐이지, 백그라운드에서는 Fetching이 진행되고 데이터가 다르다면 바뀐 데이터가 보여지게 된다.

참고
https://maxkim-j.github.io/posts/react-query-preview/
https://devkkiri.com/post/6783e9be-280a-469d-b377-dac40e7b214f

0개의 댓글