React Query
원티드 프리온보딩 챌린지를 듣고 TypeScript 까지는 잘 됐으나 React Query를 사용하는 것이 이해하기 힘들어 유튜브에 있는 우아한 테크 세미나를 듣기로 마음을 먹었다.
사실 코드를 알고 싶었으나 이론적인 내용을 잘 설명해주어 좋은 강의라는 생각이 들었다.
React Query와 상태관리
FE 상태 관리?
상태관리하면 떠오르는 것은 Redux, MobX, Recoil 라이브러리이다.
상태란?
- 주어진 시간에 대해 시스템을 나타내는 것으로 언제든지 변경될 수 있음. 즉, 문자열, 배열, 객체 등의 형태로 응용 프로그램에 저장된 데이터
⇒ 개발자 입장에선 관리해야하는 데이터들
모던 웹프론트엔드 개발
UI/UX의 중요성과 함께 프로덕트 규모가 많이 커지고 FE에서 수행하는 역할이 늘어남 → 관리하는 상태가 많아짐
상태관리는?
-
상태를 관리하는 방법에 대한 것 → 프로덕트가 커짐에 따라 어려움도 커짐
-
상태들은 시간에 따라 변화함
---value1---value2---value3--->시간의 흐름
-
React에선 단방향 바인딩이므로 Props Drilling 이슈도 존재
-
Redux와 MobX같은 라이브러리를 활용해 해결하기도 한다.
서버에서 받아야하는 상태들의 특성
- Client에서 제어하거나 소유되지 않은 원격의 공간에서 관리되고 유지됨
- Fetching이나 Updating에 비동기 API가 필요함
- 다른 사람들과 공유되는 것으로 사용자가 모르는 사이에 변경될 수 있음
- 신경 쓰지 않는다면 잠재적으로 “out of data” 가 될 가능성을 지님
⇒ 사실상 FE에서 이 값들이 저장되어있는 state들은 일종의 캐시
Client State vs Server State
Key Point는 데이터의 Ownership이 있는 곳
Client State
- Client에서 소유하며 온전히 제어 가능함
- 초기값 설정이나 조작에 제약사항 없음
- 다른 사람들과 공유되지 않으며 Client 내에서 UI/UX 흐름이나 사용자 인터렉션에 따라 변할 수 있음
- 항상 Client 내에서 최신 상태로 관리됨
Ownership이 Client에
Server State
- Client에서 제어하거나 소유되지 않은 원격의 공간에서 관리되고 유지됨
- Fetching/Updating에 비동기 API가 필요함
- 다른 사람들과는 공유되는 것으로 사용자가 모르는 사이에 변경될 수 있음
- 신경쓰지 않는다면 잠재적으로 ‘out of date’가 될 가능성을 지님
Ownership이 Server에
React Query 살펴보기
React
에서 쓰려면 QueryClientProvider
필수이다.
import { QueryClient, QueryClientProvider } from 'react-query'
const queryClient = useQueryClient();
function App() {
return <QueryClientProvider client = {queryClient}>...</QueryClientProvider>
}
React Query 세 가지 컨셉 살펴보기
- Queries
- Mutations
- Query Invalidation
1. Queries
Queries는 데이터 Fetching을 하기 위해 사용한다.
import { useQuery } from 'react-query'
function App() {
const info = useQuery('todos', fetchTodoList)
}
Query Key
Key, Value 맵핑 구조
- React Query는 Query Key에 따라 query caching 을 관리합니다.
String 형태, Array 형태 나눠져 있다.
Query Function
Data Fetching 할 때 Promise 함수 만들죠?
- Promise를 반환하는 함수 → 데이터 resolve 하거나 error를 throw
useQuery(’fetchOrder’, () ⇒ fetchOrder(orderNo), options);
- data: 마지막으로 성공한 resolved된 데이터(Response)
- error: 에러가 발생했을 때 반환되는 객체
- isFetching: Request가 in-flight 중일 때 true
- status, isLoading, isSuccess, isLoading 등등: 모두 현재 query의 상태
- refetch: 해당 query refetch하는 함수 제공
- remove: 해당 query cache에서 지우는 함수 제공
- etc.
useQuery Option
- onSuccess, onError, onSettled: query fetching 성공/실패/완료 시 실행할 Side Effect 정의
- enabled: 자동으로 query를 실행시킬지 말지 여부
- retry: query 동작 실패 시, 자동으로 retry 할지 결정하는 옵션
- select: 성공 시 가져온 data를 가공해서 전달
- keepPreviousData: 새롭게 fetching 시 이전 데이터 유지 여부
- refetchInterval: 주기적으로 refetch 할지 결정하는 옵션
- etc.
query가 여러 개일 땐?
function App() {
const usersQuery = useQuery('users', fetchUsers);
const teamsQuery = useQuery('teams', fetchTeams);
const projectsQuery = useQuery('projects', fetchProjects);
...
}
2. Mutations
Mutations는 데이터 생성/수정/삭제 시 사용한다.
const mutation = useMutation(newTodo => {
return axios.post('/todos', newTodo)
})
useQuery 보다 더 심플하게 Promise 반환 함수만 있어도 됩니다. (단, Query Key 넣어주면 devtools에서 볼수 있어요.)
- mutate: mutation을 실행하는 함수
- mutateAsync: mutate와 비슷 But Promise 반환
- reset: mutation 내부 상테 clean
- 나머진 특별히 설명할 거 없이 useQuery랑 비슷합니다. (오히려 반환하는 객체 안의 내용이 더 적어요!)
useMutation Option
- onMutate: 본격적인 Mutation 동작 전에 먼저 동작하는 함수, Optimistic update 적용할 때 유용
- 나머진 특별히 설명할 거 없이 useQuery랑 비슷합니다. (오히려 Option이 더 적어요!)
3. Query Invalidation
간단히 queryClient를 통해 invalidate 메소드를 호출하면 끝이다.
queryClient.invalidateQueries()
queryClient.invalidateQueries('todos')
이러면 해당 Key를 가진 query는 stale 취급되고, 현재 rendering 되고 있는 query들은 백그라운드에서 refetch 됩니다.
출처: https://www.youtube.com/watch?v=MArE6Hy371c
- cacheTime: 메모리에 얼마만큼 있을건지 (해당 시간 이후 GC에 의해 처리, default 5분)
- staleTime: 얼마의 시간이 흐른 후에 데이터를 stale 취급할 것인지 (default 0)
- refetchOnMount / refetchOnWindowFocus / refetchOnReconnect
→ true 이면 Mount / window focus / reconnet 시점에 Data가 stale 이라고 판단되면 모두 refetch (모두 default true)
React Query 장점
- 서버상태 관리 용이하며 (Redux, Mobx 사용할 때 보다) 직관적인 API 호출 코드
- API 처리에 관한 각종 인터페이스 및 옵션 제공
- Client Store가 FE에서 정말로 필요한 전역상태만 남아 Store 답게 사용됨 (Boilerplate 코드 매우 감소)
- devtool 제공으로 원활한 디버깅
- Cache 전략 필요할 때 아주 좋음
React Query 에 고민이 필요한 부분
- Component가 상대적으로 비대해지는 문제 (Component 설계/분리에 대한 고민 필요)
- 좀 더 난이도가 높아진 프로젝트 설계 (Component 유착 최소화 및 사용처 파악 필요)
- React Query의 장점을 더 잘 활용할 방법 (단순히 API 통신 이상의 가능성)
React Query 추천 할 만한 이유
- 수많은 전역상태가 API 통신과 였여있어 비대해진 Store를 고민하시는 분
- API 통신 관련 코드를 보다 간단히 구현하고 싶으신 분
- FE에서 데이터 Caching 전략에 대해 고민하시는 분
- (공부가 목적이라면) 모든 FE 개발자분들께
느낀점
이론을 듣고 react query 와 요즘 많이 사용하는 redux 의 차이를 조금 알 수 있었다.
원티드 프리온보딩 챌린지를 듣고 다른 분들의 코드를 봤지만 이해가 안되는 부분이 많고 공식문서를 봐도 친절하다고는 하지만 내가 사용을 할 때 어려움을 많이 느끼게 되어 실제로 많이 접해보고 활용을 해봐야 겠다는 생각이 들었다.
꼭, react query까지 진행을 하고 챌린지를 완주하고 싶다.
referece
https://techblog.woowahan.com/6339/
https://www.youtube.com/watch?v=MArE6Hy371c
https://tanstack.com/query/v4/docs/reference/useQuery