Tanstack Query - useQuery

윤태현·2024년 5월 22일
0

TANSTACK-QUERY

목록 보기
2/2
post-thumbnail

useQuery

  • 서버로부터 데이터를 조회할 때 사용
  • 데이터 조회 중 Loading, Error 등을 직접 구현하지 않아도 해당 기능을 제공
  • useQuery 공식문서에서 return 값과 인자를 참고하면 됩니다.
import { useQuery } from "@tanstack/react-query";

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

/*
- data : 서버로 부터 가져온 값, 쿼리가 성공적으로 완료 되었을 때 사용
- isLoading : 실행중인 쿼리 로딩 상태 boolean 값
- error : 쿼리 실행 중 발생한 오류를 담고 있음, 오류가 없을 경우 null
- isError : 쿼리 오류 상태 boolean 값
- queryKey : 쿼리의 고유 식별자로서 캐싱, 업데이트, 무효화 등의 작업에 쓰임. 배열 형태
- queryFn : 쿼리 함수
- 기타 옵션 인자 : 커스터마이즈를 위한 여러 옵션 (staleTime, retry, enabled 등)
*/
const { data, isLoading, error, isError } = useQuery({
  queryKey: ["posts"],
  queryFn: fetchPosts,
  retry: 2, // 실패 시 재시도 횟수
  refetchOnWindowFocus: false // 윈도우 포커스 시 자동 재조회 비활성화
});

// 로딩 상태일 때
if (isLoading) return <div>Loading...</div>;

// 에러 발생 시
if (isError) return <div>Error: {error.message}</div>;

console.log(data);

queryKey

  • 쿼리의 고유 식별자로 요청하는 데이터를 정확하게 설명해야 함
  • 배열의 형태로 사용하여 여러 개를 작성하여 동일하지 않는 key로 인식
  • 서버에 데이터를 요청할 때, 같은 쿼리 키에 대한 요청은 캐싱된 데이터를 재사용하여 불필요한 네트워크 요청을 줄임
const { data, isLoading, isError, error } = useQuery({
  queryKey: ["comments", id],
  queryFn: () => fetchComments(id),
});
  • queryFn가 어떤 변수에 의존적이라면 그 변수는 쿼리 키에 포함되어야 함

  • 만약 queryFn가 변수에 의존적이라면, 그 변수의 값이 바뀔 때마다 다른 데이터를 요청하게 되기 때문에 유동적으로 바뀌는 변수인 경우 새로운 데이터를 올바르게 요청하고 캐싱할 수 있도록 해야 함


queryFn

  • 데이터를 가져오는 비동기 함수로 필수적으로 정의되어야 함
  • Promise를 리턴
  • 인자 값을 사용하는 경우, 그 인자 값은 반드시 queryKey에 포함 되어야 함
  • queryFn 내부에서 발생하는 에러는 자동으로 캐치되어 error 상태로 관리

isFetching vs. isLoading

isFetching

  • 비동기 쿼리가 아직 해결되지 않았을 때, true
  • 캐시가 있든 없든 fetch가 해결되지 않는 경우 true
  • 아직 fetch가 완료되지 않았지만 Axios, GraphQL 호출 같은 다른 종류의 데이터를 가져오는 작업

isLoading

  • isFetching의 하위 집합으로, 로딩 중을 뜻함
  • 비동기 쿼리가 아직 미해결 상태 + 캐시된 데이터도 없을 때, true
  • 이 쿼리를 전에 실행한 적이 없어 데이터를 가져오는 중이고 캐시된 데이터도 없어서 로딩 중

fetch 진행 상태를 표현할 때, 캐싱된 값이 있어야 하는지에 대한 여부에 따라 isFetching, isLoading을 사용하면 됨


useQueries

  • 여러 개의 쿼리를 동시에 실행하고 관리할 수 있음
  • 각 쿼리는 독립적으로 관리되며, 각각의 상태 (isLoading, error, data 등)를 개별적으로 확인할 수 있음
  • 각 쿼리는 자동으로 캐싱되며, 동일한 queryKey를 가진 쿼리는 캐싱된 데이터를 재사용함
  • useQuery 공식문서에서 return 값과 인자를 참고하면 됩니다.
  • 다만 placeholderData 인자는 useQueries에도 존재하지만 useQuery처럼 이전 렌더된 쿼리들에서 정보를 넘겨 받을 수 있는건 아님

placeholderData

  • 해당 데이터는 서버 데이터와 관련 없는 보여주기용 가짜 데이터
  • useQuery로 가져오는 동안 해당 데이터를 보여주기 위해 사용 (Loading용 데이터라 생각하면 됨)
import { useQueries } from '@tanstack/react-query';

const fetchUser = async (userId: number) => {
  const response = await fetch(`https://api.example.com/users/${userId}`);
  if (!response.ok) {
    throw new Error('Network response was not ok');
  }
  return response.json();
};

const fetchPosts = async (userId: number) => {
  const response = await fetch(`https://api.example.com/users/${userId}/posts`);
  if (!response.ok) {
    throw new Error('Network response was not ok');
  }
  return response.json();
};

const UserProfile = ({ userId }: { userId: number }) => {
  const results = useQueries([
    {
      queryKey: ['user', userId],
      queryFn: () => fetchUser(userId),
    },
    {
      queryKey: ['posts', userId],
      queryFn: () => fetchPosts(userId),
    },
  ]);

  const userQuery = results[0];
  const postsQuery = results[1];

  if (userQuery.isLoading || postsQuery.isLoading) return <div>Loading...</div>;
  if (userQuery.error) return <div>Error loading user: {userQuery.error.message}</div>;
  if (postsQuery.error) return <div>Error loading posts: {postsQuery.error.message}</div>;

  return (
    <div>
      <h1>{userQuery.data.name}</h1>
      <ul>
        {postsQuery.data.map((post: any) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
};

export default UserProfile;

0개의 댓글