2월 우아한테크세미나 강의를 듣고 작성한 글입니다.
상태란?
주어진 시간에 대해 시스템을 나타내는 것으로 언제든지 변경될 수 있음
즉 문자열, 배열, 객체 등의 형태로 응용 프로그램에 저장된 데이터
모던 웹프론트엔드 개발
UI/UX의 중요성과 함께 프로덕트 규모가 많이 커지고 FE에서 수행하는 역할이 늘어남. 관리하는 상태가 많아짐. 상태관리의 필요성이 중요해졌다.
상태 관리는?
- 상태를 관리하는 방법에 대한 것 -> 프로덕트가 커짐에 따라 어려움도 커짐
- 상태들은 시간에 따라 변화함
- React에선 단방향 바인딩이므로 Props Drilling 이슈도 존재
- Redux와 MobX 같은 라이브러리를 활용해 해결하기도 함
상태관리 영역이 서버값을 저장하는데까지 확장
- API 통신 관련 코드가 모두 Store에?
- 또, 반복되는 isFetching, isError 등 API 관련 상태
- 또또, 반복되는 비슷한 구조의 API 통신 코드
상태를 두 가지로 나누어 봅시다
Client State 와 Server State
Key Point는 데이터의 Ownership이 있는 곳
1. Client State
Ownership이 Client에 있다.
- Client에서 소유하며 온전히 제어가능함
- 초기값 설정이나 조작에 제약사항 없음
- 다른 사람들과 공유되지 않으며 Client 내에서 UI/UX 흐름이나 사용자 인터랙션에 따라 변할 수 있음
- 항상 Client 내에서 최신 상태로 관리됨
2. Server State
Ownership이 Server에 있다.
- Client에서 제어하거나 소유되지 않는 원격의 공간에서 관리되고 유지됨
- Fetching이나 Updating에 비동기 API가 필요함
- 다른 사람들과 공유되는 것으로 사용자가 모르는 사이에 변경될 수 있음
- 신경 쓰지 않는다면 잠재적으로 "out of date"가 될 가능성을 지님
해답은 React Query !
Overview
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
- 서버의 데이터 가져오기, 캐시, 동기화, 데이터 업데이트
- React Query는 zero-config로 즉시 사용가능, But 원하면 언제든 config도 커스텀 가능!
React 에서 QueryClientProvider 필수 !
import { QueryClient, QueryClientProvider } from 'react-query'
const queryClient = new QueryClient()
function App() {
return <QueryClientProvider client={queryClient}>...</QueryClientProvider>
세 가지 core 컨셉 살펴보기
- Queries
- Mutations
- Query Invalidation
Queries
CRUD 중 Reading에만 사용할 것, Queries는 데이터 Fetching 용 !
- Query Key : Key, Value 맵핑구조
- Query Key에 따라 query caching을 관리한다.
useQuery('todos', ...)
useQuery(['todos', 5], ...)
useQuery(['todos', 5, { preview: true }], ...)
Query Function
Data Fetching 할 때 Promise 함수 만들죠?
- Promise를 반환하는 함수!
- 데이터를 resolve 하거나 error 를 throw
useQuery
- 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.
Mutations
CRUD 중 Create / Update / Delete 에 모두 사용
Mutations는 데이터 생성 / 수정 / 삭제 용!
const mutation = useMutation(newTodo => {
return axios.post('/todos', newTodo)
});
useQuery 보다 더 심플하게 Promise 반환 함수만 있어도 된다.
( 단, Query Key 넣어주면 devtools 에서 볼 수 있다. )
useMutation
- mutate : mutation을 실행하는 함수
- mutateAsync : mutata와 비슷 But Promise 반환
- reset : mutation 내부 상태 clean
- 나머진 특별히 설명할 것 없이 useQuery랑 비슷 (오히려 반환하는 객체 안의 내용이 더 적다.)
useMutation Option
- onMutate : 본격적인 Mutation 동작 전에 먼저 동작하는 함수, Optimistic update 적용할 때 유용
- 성공할 것이라고 Optimistic하게 보고 UI에 반영, 실패 시 롤백
(ex, 페이스북의 좋아요 기능)
- 나머진 특별히 설명할 것 없이 useQuery랑 비슷 (오히려 Option이 더 적다.)
Query Invalidation
- 간단히 queryClient를 통해 invalidate 메소드를 호출하면 끝
- 이러면 해당 Key를 가진 query는 stale 취급되고, 현재 rendering 되고 있는 query들은 백그라운드에서 refetch 된다.
- stale : 신선하지 않은, 즉 상한 데이터