React Query와 상태관리 :: 2월 우아한테크세미나를 정리한 글입니다.
https://www.youtube.com/watch?v=MArE6Hy371c
FE 상태 관리에 대하여
상태란 무엇인가?
주어진 시간에 따라 시스템을 나타내는 것으로 언제든지 변경될 수 있음.
즉, 문자열, 배열, 객체 등의 형태로 응용 프로그램에 저장된 데이터
=> 개발자 입자에서 관리해야하는 데이터들
상태 관리란?
- 상태를 관리하는 방법에 대한 것
- 상태들은 시간에 따라 변화함
- React에선 단방향 바인딩으로 props drilling 이슈도 존재
- redux 와 MobX 같은 라이브러리를 활용해 해결
상태 관리 영역이 서버값을 저장하는데까지 확장되었다.
- API 통신 관련 코드가 모두 store에 저장
- 반복되는 isFetching, isError 등 API 관련 상태 저장
- 반복되는 비슷한 구조의 API 통신 코드
서버에서 받아야하는 상태들의 특성(Server State)
- client 에서 제어하거나 소유되지 않은 원격의 공간에서 관리되고 유지됨
- Fetching이나 Updating에 비동기 API가 필요함
- 다른 사람들과 공유되는 것으로, 사용자가 모르는 사이에 변경될 수 있음
- 신경쓰지 않는다면 잠재적으로 "out of date" 가 될 가능성이 있음.
사실상 FE에서 이 값들이 저장되어 있는 state 들은 일종의 캐시
상태 비교(Client state vs Server State)
Client State
- client 에서 소유하며 온전히 제어 가능함
- 초기값 설정이나 조작에 제약이 없음
- 다른 사람들과 공유되지 않으며 client 내에서 UI/UX 흐름이나 사용자 인터렉션에 따라 변할 수 있음
- 항상 Client 내에서 최신 상태로 관리됨
React Query
server state의 데이터 가져오기, 캐시, 동기화, 데이터 업데이트를 해결해주는 라이브러리이다.
React Query 장점
- 서버상태 관리가 용이하며 직관적인 API 호출 코드
- API 처리에 관한 각종 인터페이스 및 옵션 제공
- Client Store가 FE 에서 정말 필요한 전역상태만 남아 store 답게 사용됨.
- devTools 제공으로 원활한 디버깅
- cashe 전략이 필요할 때 좋음
3가지 Core Concept
Queries, Mutaion, Query Invalidation
Query
Query 는 데이터 fetching
Query Key
- 예제의 ['todo']
- key, value 맵핑 구조로 생각
- React Query 는 Query Key에 따라 query cashing 도 관리한다.
- key 는 string 타입 또는 배열 타입으로 작성됨
Query Function
- 예제의 fetchTodoList
- Promise 를 반환하는 함수.
- data resolve 또는 error throw
useQuery 의 반환 값
- data : 마지막으로 성공한 resolved 된 데이터(response)
- error: 에러가 발생했을 때 반환되는 객체
- isFetching: Request가 in-flight 중일때 true
- status, isLoading, isSuccess 등 : 모두 현재 query의 상태
- refetch: 해당 query refetch 하는 함수 제공
- remove: 해당 query cash 에서 지우는 함수 제공
- etc.
useQuery 의 option
- onSuccess, onError, onSettled: query fetching 성공/실패/완료시에 실행할 side Effect 정의
- enabled: 자동으로 query를 실행시킬지의 여부
- retry: query 동작 실패시, 자동으로 retry 할지 결정하는 옵션
- select: 성공시 가져온 데이터를 가공해서 전달
- keepPreviousData: 새롭게 fetching시, 이전 데이터 유지 여부
- refetchInterval: 주기적으로 refetch할지 결정하는 옵션
- etc.
Quries 파일의 분리를 추천한다.
Mutation
mutation 은 데이터 생성/수정/삭제 용
useQuery와 달리 심플하게 Promise 반환 함수만 있어도 가능하다.
단, query key 를 넣어주면 devTools 에서 볼 수 있다.
useMutaion 반환값
- mutate: mutation 을 실행하는 함수
- mutateAsync: mutate와 비슷, 그러나 Promise를 반환한다.
- reset: mutation 내부 상태 clean
- etc
useMutation option
- onMutate: 본격적인 mutation 동작 전에 먼저 동작하는 함수, Optimistic Update 적용시 유용
Optimistic Update
API 호출이 성공할 것이라 판단하고 UI 를 변경.
실패시, 이전 상태로 롤백한다.
Query Invalidation
간단히 queryClient를 통해 invalidate 메서드 호출
해당 key 를 가진 query는 stale 취급.
현재 rendering 되고 있는 query 혹은 백그라운드에서 refresh
React Query는 어디에서 값을 관리하는가?
해답은 Context API, QueryClient 내부적으로 Context 사용
참고 자료
React Query 공식 문서
https://tanstack.com/query/v4/docs/quick-start
Store에서 비동기 통신 분리하기 (feat. React Query)
https://techblog.woowahan.com/6339/