etc

react-query 알아보기

Uheeking 2024. 7. 26. 11:25
반응형
반응형

[풀스택 완성] Supabase로 웹사이트 3개 클론하기 (Next.js 14) 강의 | 로펀 - 인프런

 

[풀스택 완성] Supabase로 웹사이트 3개 클론하기 (Next.js 14) 강의 | 로펀 - 인프런

로펀 | 풀스택 개발에 날개를 달아줄 Supabase! 3가지의 클론 프로젝트를 통해 Next.js 14와 Supabase로 실무 수준의 풀스택 개발을 하는 법을 속성으로 배우게 됩니다., 이 강의를 통해 여러분은[사진]Nex

www.inflearn.com

 

해당 강의를 듣고 좀 더 작성해서 쓰는 글입니다.

react-query

: react-query는 서버의 값을 클라이언트에 가져오거나, 캐싱, 값 업데이트, 에러핸들링 등 비동기 과정을 더욱 편하게 하는데 사용한다.

하위개념 설명

  • stale : 오래된 데이터를 의미한다.

사용하는 이유

React-Query는 데이터를 fetching 해온 후 데이터를 캐싱 하게 된다. 그리고 해당 데이터가 stale하다고 판단될 때 데이터를 refetching 해오게 된다. React-Query는 stale상태의 데이터를 리패칭해온다. 이말은 즉슨, 지속적으로 동기화하고 업데이트를 한다는 것이다.

셋팅하기

react-query를 사용하기 위해 프로젝트를 생성해준다.

npx create-react-app my-app
cd my-app
npm install react-query

src/index.js

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { QueryClient, QueryClientProvider } from "react-query";
import { ReactQueryDevtools } from "react-query/devtools";

const queryClient = new QueryClient();

ReactDOM.render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      {/* devtools */}
      <ReactQueryDevtools initialIsOpen={true} />
      <App />
    </QueryClientProvider>
  </React.StrictMode>,
  document.getElementById("root")
);

react-query는 api요청을 하는데, 대표적으로 useQuery와 useMutation을 많이 사용한다.

 

1. useQuery

: HTTP METHOD GET요청과 같이 서버에 저장되어 있는 상태를 불러와 사용한다.

1) 개념

const { data } = useQuery({
  queryKey, 
  fetchFn, 
  options, 
 });
  • queryKey : Query 요청에 대한 응답 데이터를 캐시할 때 사용할 Unique Key(필수항목)
  • fetchFn : Query 요청을 수행하기 위한 Promise를 Return 하는 함수(필수항목)
  • options : useQuery에서 사용되는 Option(선택항목)

2) 예시

function Users() {
  const { isPending, error, data } = useQuery(
    'userInfo', () => axios.get('/users').then(({ data }) => data),
  );
  if (isPending) return <div> 로딩중... </div>;
  if (error) return <div> 에러: {error.message} </div>;
  return (
    <div>
      {data?.map(({ id, name }) => (
        <span key={id}> {name} </span>
      ))}
    </div>
  );
}
  • userInfo : Key로 사용하여 데이터 캐싱한다.
    • key가 userInfo로 되어 있는 useQuery를 우선으로 캐싱된다.
  • if (isPending) : status를 사용하여 한번에 처리하는 것도 가능하다.
    • status === ‘loading’를 평가하여 로딩상태를 처리하는 것이 더 좋다.
    • React Query는 내부적으로 stale-while-revalidate 캐싱 전략을 사용하고 있기 때문이다.
    if (status === "loading") {
        return <span>Loading...</span>;
      }
    
      if (status === "error") {
        return <span>Error: {error.message}</span>;
      }
    

3) useQuery의 추가설명

  1. useQuery는 비동기로 작동한다. 만약, 한 컴포넌트에 여러개의 useQuery가 있다면 하나가 끝나고 다음 useQuery가 실행되지 않는다. 두개의 useQuery가 동시에 실행되게 된다.  여러개의 비동기 query가 있다면useQueries를 사용하면 된다.
const { data: nextTodo, error, isFetching } = useQuery(
  queryKey: ['repoData'],
    queryFn: () =>
      fetch('<https://api.github.com/repos/TanStack/query>').then((res) =>
        res.json(),
      ),
  {
    enabled: !!todoList 
  }

useQuery의 3번째 인자로 옵션값이 들어가는데 그 옵션의 enabled에 값을 넣으면 그 값이 true일때 useQuery를 실행된다. 여기서는 fetchNextTodoList를 실행된다.

  1. enabled옵션을 사용하면 useQuery를 동기적으로도 사용 가능하다.
const usersQuery = useQuery("users", fetchUsers);
const teamsQuery = useQuery("teams", fetchTeams);
const projectsQuery = useQuery("projects", fetchProjects);

위같은 코드 있다고 가정할 때, 이는 로딩, 성공, 실패처리를 모두 해야한다.

promise.all처럼 하나로 묶어 실행할 수 있는데, useQueries가 그러하다.

const result = useQueries([
  {
    queryKey: ["getRune", riot.version],
    queryFn: () => api.getRunInfo(riot.version)
  },
  {
    queryKey: ["getSpell", riot.version],
    queryFn: () => api.getSpellInfo(riot.version)
  }
]);

useEffect(() => {
  console.log(result); 
  const loadingFinishAll = result.some(result => result.isLoading);
  console.log(loadingFinishAll); 
}, [result]);
  • useQueries로 묶어 모든 값을 result에 담아둔다.
  • result : 출력하면 [{rune 정보, data: [], isSucces: true ...}, {spell 정보, data: [], isSucces: true ...}]이러한 값이 나온다.
  • loadingFinishAll : false면 완료된다.

useMutation

: HTTP METHOD POST, PUT, DELETE요청과 같이 서버에 Side Effect를 발생시켜 서버의 상태를 변경시킬 때 사용한다.

1) 개념

const mutation = useMutation(
  mutationFn, 
  options, 
);
  • mutationFn : Mutation 요청을 수행하기 위한 Promise를 Return 하는 함수(필수항목)
  • options : useMutation에서 사용되는 Option 객체(선택항목)

→ useMutation의 return 값 중 mutate함수를 호출하여 서버에 Side Effect를 발생시킬 수 있다.

2) 예시

const CreateTodo = () => {
  const [title, setTitle] = useState('')
  const mutation = useMutation({ mutationFn: createTodo })

  const onCreateTodo = (e) => {
    e.preventDefault()
    mutation.mutate({ title })
  }

  return (
    <form onSubmit={onCreateTodo}>
      {mutation.error && (
        <h5 onClick={() => mutation.reset()}>{mutation.error}</h5>
      )}
      <input
        type="text"
        value={title}
        onChange={(e) => setTitle(e.target.value)}
      />
      <br />
      <button type="submit">Create Todo</button>
    </form>
  )
}

useMutation의 첫번째 인자는 fetcher함수가 받는 인자이며, onError, onSettled, onSuccess를 받을 수 있다.

  • onError : fetcher함수를 실패할 때 실행하는 함수
  • onSetteled : fetcher함수를 성공하든 실패이든 무조건 실행하는 함수
  • 여기서 mutateAsync는 mutate의 결과를 포함하는 Promise를 반환한다. mutate와 똑같고, 반환하는 것이 다르므로 참고하자! 예시 코드는 다음과 같다.
useMutation(addTodo, {
   onError: (error, variables, context) => {
    // An error happened!
    console.log(`rolling back optimistic update with id ${context.id}`)
  },
  onSettled: (data, error, variables, context) => {
    // Error or success... doesn't matter!
  },
  });

3) 활용

useMutation에서 queryClient 의 invalidateQueries를 많이 사용한다.

import { AxiosError } from 'axios';
import { useMutation, UseMutationResult, useQueryClient } from 'react-query';
import { addTodo } from 'src/api/todos';
import { TodoType } from 'src/types/todoType';
import { queryKeys } from 'src/types/commonType'; 

export default function useAddTodoMutation() {
  const queryClient = useQueryClient();
  return useMutation(addTodo, {
    onSuccess: () => {
      queryClient.invalidateQueries(queryKeys.todos); 
    },  
    onError: (error) => {
      console.error(error);
    },
  });
}
  • mutation을 성공하면 todo list를 불러오는 useQuery를 무효화 시킨다.
  • • invalidateQueries 가 실행되어 쿼리가 무효화되면 해당 쿼리는 오래된 것으로 취급 된다.
  • todolist를 렌더링 하고 있던 컴포넌트는 새로운 todo 가 추가됨과 동시에 바로 해당 키값의 쿼리를 refetch 시킨다. 때문에 새로고침이나, 클라이언트 상태에 해당 데이터를 업데이트 시켜주지 않아도 된다.
  • 쿼리를 다시 refetch 하는 것을 원하지 않고 단순히 무효화만 시키고 싶을 경우에는 refetchActive: false 를 붙여주면 된다.
queryClient.invalidateQueries(queryKeys.todos, {
 refetchActive: false,
});

👇🏻 참고

https://tech.osci.kr/2022/07/13/react-query/

https://kyounghwan01.github.io/blog/React/react-query/basic/

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

https://velog.io/@kimhyo_0218/React-Query-리액트-쿼리-useMutation-실용-편custom-hook-으로-사용해보자

https://tanstack.com/query/latest/docs/framework/react/guides/mutations#mutation-scopes

https://inf.run/6SLYm

반응형