[React-Query] Query-key

상민·2022년 7월 16일
0

React Query

목록 보기
3/6
post-thumbnail

useQuery 실습

지난 실습에 이어서 이번에는 각 post의 comment를 받아오는 useQuery훅을 작성해보자

  • src/PostDetail.tsx

interface IPostDetailProps {
  post: IPost;
}
interface IComments {
  id: number;
  email: string;
  body: string;
}

async function fetchComments(postId: number) {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/comments?postId=${postId}`
  );
  return response.json();
}

export function PostDetail({ post }: IPostDetailProps) {
  // replace with useQuery
  const {data, isLoading, isError}  = useQuery<IComments[]>('comments', () => fetchComments(post.id));
 // fetchComments는 postId를 인자로 받기 때문에 익명함수로 감싸서 작성한다
  return (
    <>
      <h3 style={{ color: "blue" }}>{post.title}</h3>
      <button>Delete</button> <button>Update title</button>
      <p>{post.body}</p>
      <h4>Comments</h4>
      {
        isError && <div>ERROR!</div>
      }
      {
        isLoading ?(
          <div>Loading...</div>
        ) : (
          data?.map((comment) => (
            <li key={comment.id}>
              {comment.email}: {comment.body}
            </li>
          ))
        )
      }
    </>
  );
}

comments를 잘 받아오지만 문제가 있다.
다른 게시글을 클릭해도 처음 받아온 comment를 보여준다.

왜 같은 comment를 계속 보여줄까?

이유는 모든 쿼리가 comments 쿼리 키를 동일하게 사용하고 있기 때문이다.

이렇게 comments 같이 알려진 쿼리 키가 있을 때는 어떠한 트리거가 있어야만 데이터를 다시 가져오게 된다

  • 컴포넌트를 다시 마운트할 때
  • 윈도우를 다시 포커스할 때
  • useQuery에서 반환되어 수동으로 리페칭을 실행할 때
  • 지정된 간격으로 리페칭을 자동 실행할 때
  • Mutation을 생성한 뒤 쿼리를 무효화할 시 클라이언트의 데이터가 서버의 데이터와 불일치할 때

새 게시물 제목을 클릭할 때는 이런 트리거가 일어나지 않기 때문에 data refetch가 일어나지 않는 것이다.

해결방법

각 게시물 쿼리에 대한 라벨을 설정한다

각 쿼리에 대한 라벨을 설정하면 comments 쿼리에 대한 캐시를 공유하지 않고 각 쿼리에 해당하는 캐시를 가지게 될 것이다.

쿼리 키에 문자열 대신 배열을 전달한다
['comments', post.id]

쿼리 키를 쿼리에 대한 의존성 배열로 취급하게 된다.

이렇게 하면 모든 comments 쿼리가 같은 쿼리로 간주되는 상황을 막고 각기 다른 쿼리로 다뤄질 것이다.

  • src/PostDetail.tsx

interface IPostDetailProps {
  post: IPost;
}
interface IComments {
  id: number;
  email: string;
  body: string;
}

async function fetchComments(postId: number) {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/comments?postId=${postId}`
  );
  return response.json();
}

export function PostDetail({ post }: IPostDetailProps) {
  // replace with useQuery
  const {data, isLoading, isError}  = useQuery<IComments[]>(['comments', post.id], () => fetchComments(post.id));
 // fetchComments는 postId를 인자로 받기 때문에 익명함수로 감싸서 작성한다
 // 쿼리 키를 의존성 배열로 작성하여 post.id마다 각기 다른 쿼리를 생성
  return (
    <>
      <h3 style={{ color: "blue" }}>{post.title}</h3>
      <button>Delete</button> <button>Update title</button>
      <p>{post.body}</p>
      <h4>Comments</h4>
      {
        isError && <div>ERROR!</div>
      }
      {
        isLoading ?(
          <div>Loading...</div>
        ) : (
          data?.map((comment) => (
            <li key={comment.id}>
              {comment.email}: {comment.body}
            </li>
          ))
        )
      }
    </>
  );
}

각 게시물마다 다른 comment 쿼리를 가진다

profile
FE Developer

0개의 댓글