[TanstackQuery] 로딩, 에러, retry, useMutation

강연주·2024년 12월 11일

 🏝️ TanstackQuery

목록 보기
5/7

isPending, isError, retry

🖥️ const { error, isError } = useQuery({
  queryKey: ['posts'],
  queryFn: async (key) => {
    throw new Error('An error occurred!');
  },
})
console.log(error);
console.log(isError);

에러가 발생하면 isError 값이 true가 되고, 이에 따라 에러 메시지를 보여주도록 에러 처리를 구현한다.

🖥️ function HomePage() {
  const {
    data: postsData,
    isPending,
    isError,
  } = useQuery({
    queryKey: ['posts'],
    queryFn: getPosts,
    retry: 0,
  });

  if (isPending) return '로딩 중입니다...';

  if (isError) return '에러가 발생했습니다.';

  const posts = postsData?.results ?? [];

  return (
    <div>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>
            {post.user.name}: {post.content}
          </li>
        ))}
      </ul>
    </div>
  );
}

탠스택 쿼리에서는 에러 발생 시 기본적으로 3번의 재시도를 한다.
코드를 테스트 할 때 retry 횟수를 0으로 조정하면 에러 화면을 더 빨리 볼 수 있어서 편리하다.


useMutation()

새로운 데이터를 추가할 때 사용하는 훅. 형태나 구조 변화를 뜻하는 뮤테이션은, 여기서는 사이드 이펙트를 가진 함수를 의미한다. 데이터베이스에 새 값을 추가하거나 수정하기, 삭제하기는 사이드 이펙트에 해당되고 이렇게 사이드 이펙트가 발생할 때 useMutaion() 훅을 사용하는 것이다.

useQuery()의 쿼리 함수는 컴포넌트가 마운트되면서 자동으로 실행되는 반면,
useMutation()은 실제로 뮤테이션 하는 함수를 직접 실행해 줘야 한다는 차이점이 있다.
mutate() 함수를 통해 mutationFn으로 등록했던 함수를 실행할 수 있고, 그래야 백엔드 데이터를 실제로 수정한다.

mutate()를 하면 백엔드 데이터는 변경되지만, 현재 캐시에 저장된 데이터는 refetch를 하지 않는 이상 기존 데이터가 그대로 남아있으므로, 변경된 데이터를 화면에 반영하려면 refetch가 필요하다.

데이터 추가하기

🖥️ // 포스트 가져오는 함수
async function getPostsByUsername(username) {
  const response = await fetch(`${BASE_URL}/posts?username=${username}`);
  return await response.json();
}
🖥️ // 포스트 업로드 함수
async function uploadPost(newPost) {
  const response = await fetch(`${BASE_URL}/posts`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(newPost),
  });

  if (!response.ok) {
    throw new Error("포스트 업로드 실패");
  }

  return await response.json();
}
// 전체 코드

🖥️ import { useState } from 'react';
import { useMutation, useQuery } from '@tanstack/react-query';
import { getPosts, uploadPost } from './api';

function HomePage() {
  const [content, setContent] = useState('');
  const {
    data: postsData,
    isPending,
    isError,
  } = useQuery({
    queryKey: ['posts'],
    queryFn: getPosts,
    retry: 0,
  });

  const uploadPostMutation = useMutation({
    mutationFn: (newPost) => uploadPost(newPost),
  });

  const handleInputChange = (e) => {
    setContent(e.target.value);
  }

  const handleSubmit = (e) => {
    e.preventDefault();
    const newPost = { username: 'codeit', content };
    uploadPostMutation.mutate(newPost);
    setContent('');
  };

  if (isPending) return '로딩 중입니다...';

  if (isError) return '에러가 발생했습니다.';

  const posts = postsData?.results ?? [];

  return (
    <>
      <div>
        <form onSubmit={handleSubmit}>
          <textarea
            name="content"
            value={content}
            onChange={handleInputChange}
          />
          <button disabled={!content} type="submit">
            업로드
          </button>
        </form>
      </div>
      <div>
        <ul>
          {posts.map((post) => (
            <li key={post.id}>
              {post.user.name}: {post.content}
            </li>
          ))}
        </ul>
      </div>
    </>
  );
}

export default HomePage;

위 코드로는 업로드 버튼을 눌러도 새로 등록한 포스트가 화면에 보이지 않는다.
이는 mutate()를 한다고 캐시에 있는 데이터가 변경되는 것이 아니기 때문이다. 따라서 데이터를 refetch해야(예를 들어 화면 새로고침) 새로운 데이터도 보여줄 수 있다.


출처 : 코드잇 ReactQuery

profile
아무튼, 개발자

0개의 댓글