리액트 쿼리?
리액트 쿼리는 리액트 애플리케이션에서 비동기 상태를 관리하는 라이브러리이다. TanStack이라는 프로젝트에서 만들어진 오픈소스로, 강력한 비동기 상태 관리를 위한 패키지라고 스스로를 소개하고 있다.
리액트 쿼리를 사용하면 API 요청 상태를 더 간편하게 조회하고 응답 결과를 캐싱하고 에러에 대응할 수 있다. 리액트 쿼리는 데이터의 상태를 추적하고, 렌더링을 최적화하는 기능을 제공한다.
리액트 쿼리의 동기
리액트 애플리케이션을 개발하며 데이터를 가져오고 업데이트 하는 등 복잡한 상태 관리가 필요할 때가 많다.
- 사용자가 특정 데이터를 수정/삭제 요청을 했을때, 언제 유저의 데이터를 업데이트 해줘야 할까?
- 하나의 화면의 여러 컴포넌트에서 같은 API 요청이 사용되는데, 1번만 요청하고 결과를 공유해서 사용하고 싶다면 어떻게 해야 할까?
- 누군가 팔로우한 사실, 게임에 초대했다는 사실을 클라이언트가 어떻게 알 수 있을까? 폴링은 어떤 주기로 어떻게 구현해야 할까?
- 사용자가 6시간만에 탭을 켰는데, 데이터가 업데이트 안된다고 한다. 매번 새로고침 해줘야 할까? 화면에 나타나는 데이터가 이미 '지난' 정보라는 것을 어떻게 알고 업데이트 해줄 수 있을까?
리액트는 UI 렌더링을 위한 라이브러리로, 이러한 데이터를 가져오거나 업데이트 하는 일관된 방법을 제시하지 않는다. 다른 '프레임워크'와 구별되는 특징이기도 하다. 리액트를 사용하는 개발자는 이런 '비동기 상태' 관리 방식을 직접 구현해야 한다. 위의 네 가지 케이스 이슈는 대부분 리액트 쿼리를 통해 비교적 용이하게 해결할 수 있고 알기 쉬운 코드로 표현할 수 있다.
리액트 쿼리 이전에는 Redux, MobX 같은 상태관리 라이브러리를 가지고 해결했다. 비동기 상태관리에 특화된 리액트 쿼리 보단, 상태관리 전반을 위한 도구이기 때문에 위에서 말한 세부적인 처리를 직접 구현해야 했다. 비슷한 요구사항에 대해 일관성이 떨어지게 구현하게 되면서, 의도치 않은 버그를 일으키기도 좋다.
- 서버에 요청해서 변화를 일으켰을 때, 클라이언트에 저장한 데이터를 최신화하지 않는 실수
- 무의미한 또는 과도한 API 요청 / 메모이제이션
- side effect를 추적하기 힘들어 부담스러움
- API 요청마다 서로 다른 추상화 수준, 인터페이스
위와 같은 데이터 요청 및 상태 업데이트의 복잡성, 중복 코드의 증가, 오류 처리 등의 문제를 발생시키는데, 리액트 쿼리는 이러한 문제를 해결하고자 등장했다.
리액트 쿼리의 장점
✅ 간편한 데이터 관리
API 요청과 데이터 캐싱, 상태 관리 등을 자동화하여 개발자들이 데이터를 쉽게 가져오고 업데이트 할 수 있도록 도와준다. 캐싱이 자동으로 이루어지고, 옵션으로 설정 가능하기 때문에 잦은 요청을 줄이면서도, 필요한만큼 자주 캐시를 최신화하도록 해서 사용자에게 최적화된 정보를 제공할 수 있다.
리액트 쿼리는 리액트를 위한 Hook을 제공한다. 직접 데이터 상태 관리를 위한 복잡한 훅을 작성하지 않아도 되고, 일관된 방식으로 쿼리할 수 있다. 대표적으로 `useQuery` 와 `useMutation` 이 있다.
const {
data, // queryFn 요청의 결과 데이터
error, // queryFn 요청의 에러 발생 시, error 값
refetch, // 명시적으로 query를 다시 실행하기위한 함수
status // query호출의 상태를 표현함. "error","success","loading" 중 하나.
} = useQuery({
queryKey : ['todo'],
queryFn : fetchSomething,
staleTime: 0, // 위 2번째 `data`를 stale 상태로 인식하기까지 시간 (fresh -> stale)로 변하면 refetch시 data가 업데이트될 수 있다.
refetchInterval: false, // refecth 인터벌을 number, false, 함수 형태로 전달할 수 있다. polling을 구현하기 용이하다.
})
✅ 상태 관리 및 오류 처리의 용이성
리액트 쿼리는 데이터 상태를 추적하고 관리하는데 도움을 준다. 데이터 요청 및 업데이트 중에 발생하는 오류를 처리하고, 로딩 상태 및 성공 또는 실패 상태를 수비게 확인할 수 있다. 에러 핸들링 및 데이터 상태를 효율적으로 관리할 수 있게 도와준다.
서버 상태를 관리할 때 자주 사용하는 패턴이 추상화되어 있어서 같은 코드를 짧게 표현할 수 있다. 쿼리 자체를 비활성화 시킬 수 있는 `enabled` 나 `onError` `onSuccess` 같이 비동기 작업(서버 요청) 결과에 대해 대응하는 코드를 작성하기 용이하다.
const query = useQuery({
queryKey : ['todo'], // 쿼리의 키로서, 쿼리를 구분하는 역할을 합니다. 키가 다르면 다른 쿼리이니까, 키에 연결된 쿼리데이터도 별도로 관리됩니다.
queryFn : fetchSomething, // 어떤 함수든 들어갈 수 있습니다. 비동기 함수라면, 비동기 작업 중에는 status가 loading이 됩니다.
enabled : true, // 기본값으로 true입니다. 경우에 따라서, 옵션을 끌 수 있는데, 예를 들어 요청하는 데이터의 id가 주어지지 않았다면, 요청을 해도, 실패하니까 요청할 필요가 없겠죠
onError : (error) => alert('에러입니다'), // queryFn의 결과가 에러인 경우에 호출될 콜백입니다.
onSuccess: (data) => console.log(`성공 데이터:${data}`)// queryFn의 결과가 성공인 경우에 호출될 콜백입니다.
})
✅ 사용자 경험 향상을 위한 기능 제공
대표적으로 다음과 같은 UX 개선에 도움되는 기능을 구현하기 쉽게 제공한다.
- `refetchOnWindowFocus` : 브라우저 탭을 다시 띄웠을 때, 쿼리를 다시 호출해 최신화한다. 새로고침 없이 업데이트된 데이터를 접하게 된다.
- `retry` : 기본적으로 3회 - 1초, 4초, 6초 간격으로 실패한 요청에 대해 다시 요청한다. 별도의 재시도가 필요 없다.
- `Optimistic Update` : 서버 데이터를 업데이트할 때, 요청이 성공한다고 희망적으로 가정하고 쿼리 데이터에 반영하는 패턴이다. 실제로 요청이 실패하면 롤백하기 용이한 방법을 제공한다. 덕분에 유저는 성공케이스에 더 빠르게 접하는 경험을 하게 된다.
리액트 쿼리에서 제공하는 이러한 기능들은 자주 사용되거나, 일반적인 요구사항을 더 쉽게 구현하게 해주고 개발자들이 핵심적인 비즈니스 로직에 집중하게 도와준다. 결과적으로 리액트 쿼리는 데이터 요청, 상태 관리, 오류 처리 등의 작업을 간소화해서 개발자들이 더 효율적으로 애플리케이션을 개발하도록 도와준다.
https://tanstack.com/query/latest/docs/framework/react/overview
Overview | TanStack Query Docs
tanstack.com
'Today I Learned' 카테고리의 다른 글
서버 상태와 클라이언트 상태의 차이 (0) | 2024.02.14 |
---|---|
두 번째 팀 프로젝트 회고 (0) | 2024.01.30 |
상태 관리 라이브러리, Jotai (0) | 2023.12.14 |
CORS 에러 (0) | 2023.12.12 |
Next.js의 서버 사이드 렌더링(SSR) (0) | 2023.11.29 |