동기
react app은 데이터 비동기 서버 통신에 대한 구체적인 방법을 제공하지 않음
-> 데이터 통신을 위해 react hook 또는 상태관리 라이브러리를 사용함
상태관리 라이브러리는 클라이언트 상태 작업에만 최적화 되어있어 비동기 또는 서버 상태 작업에는 적합하지 않음
서버 상태를 관리하기 위한 라이브러리
사용하는 이유
store에서 클라이언트 데이터와 서버 데이터가 공존하여 혼론을 야기함
-> react-query를 통해 클라이언트 데이터와 서버 데이터를 분리함
-> 서버 데이터를 위한 store 내 로직이 과도하게 커지고 그로 인해 store를 사용하기 위한 보일러 플레이트가 비대해지기 때문
-> 서버응답을 store에서 관리가 필요 없는경우에도 구조화를 위해 불필요한 캐싱도 일어남
따라서, 관리할 서버 데이터가 비대한 경우 사용
장점
- 사용자들에게 더 빠른 응답을 느끼도록 함
- 대역폭을 절약하고 메모리 성능을 높이는데 도움이됨
- 캐싱
- get 한 데이터에 대해 update 이후 자동으로 get을 수행
- 데이터가 오래되었다고 판단되면 다시 get을 하여 최신화
- 동일한 데이터가 여러번 요청되면 실제 요청은 한번만 함
- 무한 스크롤
- 비동기 과정을 선언적으로 관리
- 에러 핸들링이 간결함
캐싱
데이터가 stale(유효기간이 지남) 하다고 판단될때 데이터를 refetching
캐싱 관련 옵션
- refetchOnWindowFocus - 브라우저에 focus event 가 발생한 경우 (default: true)
- refetchOnMount - 새로 마운트된 경우 (default: true)
- refetchOnReconnect - 네트워크가 다시 연결된 경우 (default: true)
- staleTime
- cacheTime
client Data 와 server data 분리
서버에서의 데이터를 useQuery를 이용해 통신하여 로직을 분리하고
필요한 경우에만 store(client data)에서 관리
hooks
useQuery
- 데이터를 get 하기 위한 hook
- param
- unique Key: string | array
- 비동기 함수(promise 객체)
- option
- return
- api의 성공, 실패, response 값을 포함한 객체
- 비동기로 작동함
- 하나의 component에서 여러 useQuery를 사용하는 경우
- -> 여러 useQuery가 동시에 실행됨
- 따라서 여러개의 비동기 query를 실행하는 경우 useQueries 를 사용
- option param enabled를 사용하여 useQuery를 동기적으로 사용이 가능
- refetch 함수를 트리거로 사용해야함
- mount, window focus 되어도 쿼리가 자동실행되지 않음
function Todos() {
// isLoading, isSuccess 대신 status로 한번에 처리
const { status, data, error } = useQuery("todos", fetchTodoList);
if (status === "loading") {
return <span>Loading...</span>;
}
if (status === "error") {
return <span>Error: {error.message}</span>;
}
return (
<ul>
{data.map(todo => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
}
useQueries
useQuery를 비동기로 여러개 실행하는 경우
// 아래 예시는 롤 룬과, 스펠을 받아오는 예시입니다.
const result = useQueries([
{
// unique key를 배열로 전달하여 riot.version 이 query 함수 내부에서 변수로 사용 가능
queryKey: ["getRune", riot.version],
queryFn: params => {
console.log(params); // {queryKey: ['getRune', '12.1.1'], pageParam: undefined, meta: undefined}
return api.getRunInfo(riot.version);
}
},
{
queryKey: ["getSpell", riot.version],
queryFn: () => api.getSpellInfo(riot.version)
}
]);
useEffect(() => {
console.log(result); // [{rune 정보, data: [], isSucces: true ...}, {spell 정보, data: [], isSucces: true ...}]
const loadingFinishAll = result.some(result => result.isLoading);
console.log(loadingFinishAll); // loadingFinishAll이 false이면 최종 완료
}, [result]);
query cache
query에 대한 성공, 실패 전처리
const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: (error, query) => {
console.log(error, query);
if (query.state.data !== undefined) {
toast.error(`에러가 났어요!!: ${error.message}`);
},
},
onSuccess: data => {
console.log(data)
}
})
});
useMutation
값을 변경할때 사용하는 hook -> update, post ...
적용하기 좋은 케이스
client data 보다 server data 관리가 더 많을 경우
-> admin 같이 client 전역 상태가 적은 경우 Ducks 구조보다는 더 구조가 단순해짐
참고자료
https://tanstack.com/query/v4/docs/overview
Overview | TanStack Query Docs
React Query is often described as the missing data-fetching library for React, but in more technical terms, it makes fetching, caching, synchronizing and updating server state in your React applications a breeze. Motivation
tanstack.com
react-query 개념 및 정리
react-query 개념 및 정리, react, react16, hook, useState, useRef, useMemo, useEffect, useReducer, useCallback, useQuery 동기적으로 실행
kyounghwan01.github.io
https://tech.kakao.com/2022/06/13/react-query/
My구독의 React Query 전환기
안녕하세요, 톡FE파트에서 My구독, 이모티콘 스토어를 개발하고 있는 Hugo입니다.My구독은 정기 결제를 통해 ‘이모티콘 플러스’, ‘톡서랍 플러스' 서비스를 이용할 수 있는 구독형 서비스입니
tech.kakao.com
https://tech.osci.kr/2022/07/13/react-query/
React-Query 도입을 위한 고민 (feat. Recoil) - 오픈소스컨설팅 테크블로그 - 강동희
Web Frontend 개발을 할 때 React 를 사용하면서 마주하게 되는 여러 가지 문제점 중 하나는 state, 상태 관리에 관한 부분입니다. 프론트엔드 개발자라면 state 와 뗄 수 없는 인연을 맺고 있습니다.오늘
tech.osci.kr