HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
👻
개발 기록
/
📚
CS 스터디
/
📚
react query
📚

react query

useQuery

개념

  • react에서 비동기 로직(서버 상태 가져오기, 캐싱, 동기화, 업데이트)을 쉽게 다루게 해주는 라이브러리.
const { data, isLoading, status, error, isFetching } = useQuery(queryKey, queryFunction, options)
  • queryFunction에는 서버에 데이터를 요청하고 Promise 또는 에러를 반환하는 함수를 전달함.
  • queryKey에는 문자열과 배열을 넣을 수 있음. queryKey의 유연성이 캐싱 처리를 도와주는 핵심 역할. queryKey의 조합에 따라 key가 다르면 캐싱도 별도 관리하기 때문.

반환값

  • data : queryFunction이 반환한 Promise resolve 데이터.
  • isLoading : 캐시된 데이터가 없는 상태에서 데이터를 요청중일 때 true.
  • isFetching : 캐시 데이터 유무와 상관없이 데이터를 요청중일 때 true.

옵션

  • cacheTime : 기본값은 5분으로, unused / inactive 캐시 데이터를 메모리에서 유지시킬 시간.
    • Infinity로 설정하면 쿼리 데이터가 캐시에서 제거되지 않음.
  • staleTime : 기본값은 0으로, 쿼리 데이터가 fresh에서 stale로 전환되는데 걸리는 시간.
    • Infinity로 설정하면 쿼리 데이터는 직접 캐시를 무효화할 때까지 fresh 상태로 유지.
    • 캐시는 메모리에서 관리되므로 브라우저 새로고침 후에는 다시 가져옴.
  • onSuccess : queryFunction이 성공적으로 데이터를 가져왔을 때 호출되는 함수.
  • onError : queryFunction에서 오류가 발생했을 때 호출되는 함수.
  • onSettled : queryFunction이 성공, 실패한 경우 모두 실행되는 함수.
  • keepPreviousData : queryKey가 변경되어 새로운 데이터를 요청하는 동안에도 마지막 data값을 유지.
    • 페이지네이션을 구현할 때 유용함. 캐시되지 않은 페이지를 가져올 때 화면에서 viewing 컴포넌트가 사라지는 현상을 방지할 수 있다.
    • isPreviousData값으로 현재의 queryKey에 해당하는 값인지 확인할 수 있다.
  • initialData : 캐시된 데이터가 없을 때 표시할 초기값. placeholder와는 달리 캐싱 가능. 브라우저 로컬 스토리지에 저장해 둔 값으로 데이터를 초기화할 때 사용할 수 있음.
  • refetchOnWindowFocus : 윈도우가 다시 포커스되었을 때 데이터를 호출할 것인지 여부. 기본값은 true.

예시

  • npm i react-router-dom react-query, yarn add react-query
  • 캐시를 관리하기 위하여 QueryClient 인스턴스를 사용.
  • 이 때, 컴포넌트가 useQuery hook 안에서 QueryClient 인스턴스에 접근 가능하도록 만드는 QueryClientProvider를 컴포넌트 트리 상위에 추가해야 함.
  • setState와 useEffect로 정의한 부분을 제거할 수 있음.
  • 캐싱하기 때문에 다시 api를 호출하지 않음.
import { QueryClient, QueryClientProvider } from "react-query"; import App from "./App"; const queryClinet = new QueryClient(); ReactDOM.render( <React.StrictMode> <QueryClientProvider client={queryClinet}> <App /> </QueryClientProvider> </React.StrictMode>, document.getElementById("root")
  • useQuery라는 hook이 fetcher함수 fetchCoins를 불러오고, 로딩중이라면 isLoading에서 알려줌. 또한 fetchCoins가 끝났다면 react query가 역시 말해줄 것임.
  • fetchCoins가 끝나면 react query는 그 함수의 데이터를 data에 넣어줌.
  • ts에선 data의 타입을 모르기 때문에 coin Interface를 정의해주면 됨.
  • Devtool로 캐싱된 데이터를 볼 수도 있음.
    • import { ReactQueryDevtools } from "react-query/devtools"; <> <GlobalStyle /> <Router /> <ReactQueryDevtools initialIsOpen={true} /> </>
      notion image
  • 세번째 파라미터로 refetchInterval를 사용하여 realtime을 구현할 수 있음. 예를 들어 5000을 값으로 전달하면 5초마다 갱신됨.
⚠️ overload가 뜬다면? 원하는 타입으로 전달이 된 것이 아님!

useMutation

const mutation = useMutation(newTodo => axios.post('/todos', newTodo)) const handleSubmit = useCallback( (newTodo) => { mutation.mutate(newTodo) }, [mutation], )
  • 서버에서 데이터를 가져오는 것은 단순히 useQuery를 사용하면 될테지만, 서버의 데이터를 업데이트 하는 경우에는 동일한 방식을 사용하는 것이 적절치 않음.
  • 데이터의 생성/수정/삭제 (CUD) 시에는 “useMutation” hook을 사용.
  • onSuccess, onError, onSettled, onMutate 콜백 사용.
  • useMutation을 사용한다면 onSuccess 콜백말고, mutateAsync 함수를 사용하는 것이 가독성에 좋음.
const mutation = useMutation(newTodo => axios.post('/todos', newTodo)) const handleSubmit = useCallback( async (newTodo) => { await mutation.mutateAsync(newTodo) setAnotherState() dispatch(createAnotherAction()) }, [mutation], )
 
참고자료 :
[React-Query] 리액트로 비동기 다루기