React Query 뿌수기

문다현·2024년 1월 18일
0
post-thumbnail

📚 정의

React Query는 서버 상태 관리를 위한 서드파티 리액트 라이브러리다.

서버 상태를 가져오고(fetch), 캐싱하고, 동기화하고(synchronize)하고 업데이트 하는 것을 용이하게 만들어준다.

👀 기존의 상태관리 라이브러리

기존의 상태관리 라이브러리는 클라이언트 상태 관리에는 적합할 수 있지만 비동기나 서버 상태 관리하는데는 적합하지 않다. 서버의 상태는 클라이언트의 상태와 매우 다르기 때문에 관리가 쉽지 않다. (캐싱, 쿼리 결과 등등..)
이렇게 너무나도 다른 클라이언트 상태와 서버 상태가 함께 담길수 밖에 없는 상황이 생긴다.

Redux

대표적인 전역 상태관리 라이브러리인 Redux의 경우를 살펴보자

  • Boilerplate 코드가 너무 장황하다 -> 코드가 눈에 잘 들어오지 않는다
  • API 통신 및 비동기 상태 관리를 위한 라이브러리가 아니다 -> 비동기 데이터를 관리하기 위해서는 관련된 코드를 하나부터 열까지 개발자가 결정하고 커스텀하여 구현해야 합니다.
    상황에 따라 데이터를 관리하는 방식과 방법이 달라질 수 밖에 없다

💎 React Query의 장점

리액트쿼리를 쓰면 클라이언트 상태와 서버 상태를 분리할 수 있다
코드가 비교적 양이 적고 단순하다 -> 유지보수에 용이하다

서버 데이터를 담을 상태를 만들고 useEffect로 상태에 데이터를 담는 모든 과정을 useQuery 단 한줄로 처리할 수 있다.
비동기과정을 선언적으로 관리할 수 있다.
리액트 앱 내부에서 http 요청을 간편하게 보낼 수 있다

만약 홈 페이지에서 세부페이지를 클릭해서 들어갔다가 다시 홈페이지로 이동할 때 즉각적으로 화면이 띄워진다

당연한거아닌가요?

→ 아니다. 이전에 UseEffect를 fetch를 쓸때는 이렇지 않음. 계속 요청을 새로 보냈어야 했음!

물론!! 이것들은 다 fetch나 useEffect로도 구현이 가능하다
useQueryClient를 사용해서 필요시 데이터를 불러올 수 있다.

☘️React Query Hook

React Query는 API 요청을 Query 그리고 Mutation 이라는 두 가지 유형으로 나뉜다.

1️⃣ Query

useQuery Hook으로 수행되는 Query 요청은 HTTP METHOD GET 요청과 같이 서버에 저장되어 있는 “상태”를 불러와 사용할 때 사용한다
React Query는 이 Unique Key로 서버 상태 (aka. API Response)를 로컬에 캐시하고 관리한다.

query option ⬇️
https://tanstack.com/query/latest/docs/react/reference/useQuery

2️⃣ Mutation

useMutation Hook으로 수행되는 Mutation 요청은 HTTP METHOD POST, PUT, DELETE 요청과 같이 서버에 Side Effect를 발생시켜 서버의 상태를 변경시킬 때 사용한다. useMutation Hook의 첫번째 파라미터는 이 Mutation 요청을 수행하기 위한 Promise를 Return 하는 함수이며, useMutation의 return 값 중 mutate(또는 mutateAsync) 함수를 호출하여 서버에 Side Effect를 발생시킬 수 있다.

mutation option ⬇️
https://tanstack.com/query/latest/docs/react/reference/useMutation

🎬 시작하는 법

설치

npm i @tanstack/react-query
# or
pnpm add @tanstack/react-query
# or
yarn add @tanstack/react-query

기본설정

const queryClient = new QueryClient();

export default function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <Contents />
    </QueryClientProvider>
  );
}

const queryClient = new QueryClient();

QueryClient 인스턴스를 생성한다.

QueryClient는 데이터 캐싱, 요청 관리 및 상태 관리를 담당하는 핵심 객체다.

<QueryClientProvider client={queryClient}> </QueryClientProvider>

QueryClientProvider 컴포넌트를 사용하여 애플리케이션에 queryClient를 제공한다.(이 컴포넌트는 React Query의 기능을 사용하기 위해 필요한 컨텍스트를 제공한다.)

client prop을 사용하여 생성한 인스턴스를 넘겨준다.

이제 직접 활용을 해보자!!

댓글을 불러오고(GET), 생성하고(POST), 삭제하는(DELETE) 과정을 보겠다.

리액트쿼리는 쿼리에서는 http 요청을 전송하는 로직이 없다. 요청을 관리하는 로직만이 존재한다. 그래서 요청을 전송하는 로직은 직접 짜야한다.

댓글 리스트를 fetch하는 http 요청 로직이다. 이 요청을 queryFn으로 보내면 된다. 이 때 이 함수는 프로미스를 반환해야 한다. 주의하자

const fetchCommentList = async (postId: string) => {
try {
  const token = localStorage.getItem('accessToken');

  const response = await client.get<GetCommentListResponseTypes>(`/api/post/${postId}/comment`, {
    headers: {
      Authorization: `Bearer ${token}`,
    },
  });
  return response.data;
} catch (err) {
  console.log(err);
}
};

export default fetchCommentList;

✅ useQuery를 사용해서 댓글 GET

//글에 해당하는 댓글 리스트 조회 api
export const useGetCommentList = (postId: string) => {
 const data = useQuery({
   queryKey: ['comment_postId", postId],
   queryFn: () => fetchCommentList(postId),
 });

 const commentListData = data.data?.data.comments;
 return { commentListData };
};
 const { commentListData } = useGetCommentList(postId || '');

queryKey:

queryKey는 쿼리를 고유하게 식별하는 데 사용되는 값입니다.
배열 형태로 제공되며, 배열의 각 요소는 쿼리의 일부를 나타냅니다.

쿼리가 재호출되면 queryKey가 변경되지 않으면 React Query는 이전에 캐시된 데이터를 사용하여 불필요한 중복 호출을 피하려고 시도합니다.

첫 번째 요소는 쿼리를 고유하게 식별하기 위한 문자열 , 두번째 요소는 실제로 쿼리에 필요한 변수를 나타냅니다. 이 변수는 쿼리가 실행될 때 동적으로 값이 할당됩니다

✅ useMutation을 사용하여 댓글 POST

//댓글 생성 api
export const usePostComment = (postId: string) => {
const queryClient = useQueryClient();
const data = useMutation({
  mutationKey: ['comment_postId", postId],
  mutationFn: (comment: string) => fetchPostComment(postId, comment),
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: ['comment_postId", postId] });
  },
});

const postComment = (comment: string) => {
  data.mutate(comment);
};

return { postComment };
};

mutationKey는 배열 형태로 제공되며, 배열의 첫 번째 요소는 쿼리 또는 뮤테이션의 이름을 나타내는 문자열이어야 한다. 두 번째 요소는 해당 쿼리 또는 뮤테이션을 실행할 때 필요한 변수 등을 포함할 수 있다다.

이 코드에서는 "postComment" 뮤테이션을 실행하고 postId를 변수로 전달하여 해당 댓글을 가져오는 작업을 수행한다.

const { postComment } = usePostComment(postId || '');

queryClient.invalidateQueries를 사용하여 해당 게시물의 댓글 리스트를 갱신하도록 요청합니다. 이로 인해 댓글이 생성되면 자동으로 댓글 리스트를 새로고침하여 최신 데이터를 가져온다.
여기서의 쿼리키는 댓글리시트를 get할때 사용한 쿼리키를 써야 한다.

✅ useMutation을 사용하여 댓글 DELETE

//댓글 삭제 api
export const useDeleteComment = (commentId: string, postId: string) => {
 const queryClient = useQueryClient();
 const data = useMutation({
   mutationKey: ['comment_postId", commentId],
   mutationFn: () => fetchDeleteComment(commentId),
   onSuccess: () => {
     queryClient.invalidateQueries({
       queryKey: ['comment_postId", postId],
     });
   },
 });

 const deleteComment = () => {
   data.mutate();
 };
 return { deleteComment };
};
  const { deleteComment } = useDeleteComment(commentId || '', postId || '');

delete도 바로 반영이 되게끔 invalidateQueries 를 사용해주었다.

📚 references:

https://tanstack.com/query/v3/docs/react/overview

https://tech.kakaopay.com/post/react-query-1/#react-query-소개

https://lasbe.tistory.com/163

https://www.nextree.io/react-query/

profile
기록 남기기

0개의 댓글