[React-Query] react-query v3로 서버상태관리하기

Gyuhan Park·2023년 9월 2일
1

nextjs

목록 보기
5/10

💭 TMI

react-query 를 매번 하고싶었는데 못했다.
항상 일단 axios로 API 요청 처리하고 나중에 시간되면 react-query 넣어야겠다~고 생각하는데 프로젝트가 끝나고나서 코드를 들여다보기가 쉽지 않다.
근데 이번엔 의욕이 더 강했나? 대회는 끝났지만 코드를 개선하고 싶은 마음이 굴뚝같다. 이번 프로젝트에 애정이 생겨버렸나봐 😎

공식문서를 읽으면서 적다보니 모든 내용을 담으려다가 해석하는 글이 되버리는 것 같아서 핵심개념과 적용해본 부분만 작성하고 추후에 더 작성할 예정이다 :)

✵ react-query

"it makes fetching, caching, synchronizing and updating server state in your React applications a breeze."

-> 서버 상태를 가져와 캐싱, 동기화 및 업데이트하는 작업을 쉽게 만들어준다.

서버 데이터를 가져올 때 일반적으로 컴포넌트 기반 state와 side-effect를 묶어 사용하거나, 앱 전체에서 비동기 데이터를 저장하고 제공하기 위해 일반적인 목적의 상태 관리 라이브러리를 사용했다.

redux , recoil 등으로 클라이언트 데이터의 상태를 관리했다면,
react-query 로는 서버 데이터의 상태를 관리함으로써 관심사를 분리할 수 있다.

📌 useQuery

일반적으로 GET 요청을 보낼 때 사용한다.

// 인자로 key, function, option 순서대로 넣으면 된다
const { data } = useQuery(queryKey, queryFunction, option)

// 또는 객체를 담아 순서와 관계없이 넣을 수도 있다
const { isLoading, error, data } = useQuery({
	queryKey: ['key'],
	queryFn: () =>  fetch('https://api.github.com/repos/tannerlinsley/react-query').then(
        (res) => res.json(),
	),
})

첫 번째 인자로는 id값을 의미하는 query key 를 넣고, 두 번째 인자로 query function 인데 Promise를 리턴하는 비동기 함수를 넣어야 된다.

useQuery의 리턴값으로는 아래의 값 외에 많은 상태값들이 존재하는데, isLoading 값을 사용하면 데이터 fetching 할 때 로딩을 따로 state값으로 두지 않아도 되서 편하다. 이 중에서 필요한 값들을 구조분해할당을 이용하여 가져올 수 있다.

useQuery는 두 번째 인자로 전달한 getRecommendPlace 라는 비동기 함수의 응답값을 data 라는 프로퍼티로 반환한다.
아래와 같이 구조분해할당으로 data 값을 받아서 place 라는 이름으로 변환할 수 있고, 타입을 지정할 수 있다.

const { data:place } = useQuery(['queryKey'], getRecommendPlace);

const {data: place}: {data: IPlace[]} = useQuery(['queryKey'], getRecommendPlace);

📌 useMutation

Unlike queries, mutations are typically used to create/update/delete data or perform server side-effects.

POST , PUT , DELETE 요청을 보낼 때 사용한다.

const mutation = useMutation({
	mutationFn: (newTodo) => {
		return axios.post('/todos', newTodo)
    },
})

useMutation은 안써봤지만 useQuery만큼의 강력함은 크게 와닿지 않는다고 한다(?)

📌 query key

useQuery를 사용하면 해당 hooks의 queryKey 를 지정하게 된다.

React Query에서는 query key를 기반으로 해서 쿼리 캐싱을 관리한다.
해당 key는 내부적으로 데이터 재요청, 캐싱, 쿼리를 공유하기 위해 사용된다.

If your query function depends on a variable, include it in your query key.

queryKey는 queryFunction의 변수도 포함한다. 두 번째 query function의 매개변수로 들어가는 값도 query key에 포함되어야한다는 것이다.

const { data: recommendPlaces } = useQuery(['recommendPlaces', 2], () => getRecommendPlace(2));

📌 important default

그만 쓰려고 했는데 공식문서에서 중요하다는데 안볼 순 없겠죠?

  • useQuery 또는 useInfiniteQuery를 통해 쿼리 인스턴스를 생성할 때,
    기본적으로 캐시된 데이터를 만료된(stale) 데이터로 간주한다.
  • 만료시간( staleTime ) 을 지정할 수 있다.

만료된 쿼리는 다음 상황에서 자동으로 백그라운드에서 다시 가져온다

  • 쿼리의 새로운 인스턴스가 마운트될 때 ( refetchOnMount )
  • 창이 다시 포커스될 때 ( refetchOnWindowFocus )
  • 네트워크가 다시 연결될 때 ( refetchOnReconnect )
  • 쿼리가 선택적으로 리페치(refetch) 간격으로 구성되어 있을 때 (refetchInterval )

더 이상 활성 상태가 아닌 쿼리 결과는 inactive 으로 표시되며 나중에 다시 사용될 수 있도록 캐시에 남는다.
"inactive" 쿼리는 5분 후 에 가비지 컬렉터에 의해 제거된다.
cacheTime 을 milliseconds 단위로 설정할 수 있다.

🔥 그래서 왜 쓰는데?

  1. fetch 로직 단순화
  2. 데이터 캐싱
  3. 서버데이터 분리

react-query를 도입하기 전에 서버에서 데이터를 가져오려면 이런 과정을 거쳤다.
1. 서버에 API 요청
2. useEffect 로 컴포넌트가 mount 될 때 fetching
2. 응답받은 데이터를 클라이언트에서 state로 관리.

const [data, setData] = useState<IData[]>([]);

useEffect(() => {
	getServerData().then((res) => setData(res))
  }, [])

가독성 측면에서 많은 이점이 있다.
상태가 많아지면 server state와 client state가 섞이면서 헷갈리고 useEffect() 가 있으면 코드 읽을 때 흐름에 방해가 된다. 설정할 것도 거의 없고 단순해서 코드를 많이 줄일 수 있다.

npm i react-query # v3
npm i @tanstack/react-query # latest
// _app.tsx
import { QueryClient, QueryClientProvider } from 'react-query';

const queryClient = new QueryClient();
const Reactproject: NextPage<AppProps> = ({ Component, pageProps }: AppProps) => {
  return (
        <QueryClientProvider client={queryClient}>    
            <Component {...pageProps} />
        </QueryClientProvider>
    );
};

위와 같이 최상단의 컴포넌트를 QueryClientProvider 로 감싸준다.

const { data } = useQuery(['queryKey'], getRecommendPlace);

그러고 컴포넌트에서 useQuery를 갖다쓰면 끄읏

🚨 라이브러리 버전 업그레이드

react-query 공식문서를 맨처음 들어가면 v3 버전으로 나온다. 왼쪽 사이드바를 보면 버전을 변경할 수 있는데 v4, v5는 실험버전이라고 하고 현재 latest 버전은 v4 라고 한다. npm으로 그냥 설치하면 v3버전으로 설치가 되지만 변경 사항을 한번 살펴보자.

📌 라이브러리 이름 변경

v3버전에서는 react-query에서 import를 하고 있는데 v4버전에서는 @tanstack/react-query 로 이름이 변경되었다.
v3버전에는 react만 있고 latest에는 다른 라이브러리가 추가된 걸 보니 react 말고도 사용할 수 있다는 의미로 변경했다고 추측된다.

📌 Query key에 배열 넣기

query key에 string을 넣었었는데 값이 1개여도 배열에 담아서 넣어야 한다.

const { data } = useQuery(['queryKey'], getRecommendPlace);

📌 useQueries에 queries 명시

useQueries({ queries: [{ queryKey1, queryFn1, options1 }, { queryKey2, queryFn2, options2 }] })

📌 undefined 대신 Error 반환

쿼리를 잘못 작성했을 때 undefined가 나오는 경우가 있는데 이때 error를 반환한다.

react-query 공식문서
react-query 개념정리
react-query 푹찍어먹기
카카오페이 FE개발자가 react-query를 선택한 이유

profile
단단한 프론트엔드 개발자가 되고 싶은

1개의 댓글

comment-user-thumbnail
2023년 9월 3일

우와~ 유용한 정보네요^^
가독성 측면에서 이점이 있군요. 꼭 적용해보겠습니다! 좋은 글 감사합니다 ~ㅎㅎ

답글 달기