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 세 가지 컨셉 살펴보기

  1. Queries
  2. Mutations
  3. Query Invalidation

1. Queries

Queries는 데이터 Fetching을 하기 위해 사용한다.

import { useQuery } from 'react-query'

function App() {
	const info = useQuery('todos', fetchTodoList)
} 
// ‘todos’ ⇒ Query Key
// fetchTodoList ⇒ Query Function

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);

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.

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에서 볼수 있어요.)

useMutation

  • mutate: mutation을 실행하는 함수
  • mutateAsync: mutate와 비슷 But Promise 반환
  • reset: mutation 내부 상테 clean
  • 나머진 특별히 설명할 거 없이 useQuery랑 비슷합니다. (오히려 반환하는 객체 안의 내용이 더 적어요!)

useMutation Option

  • onMutate: 본격적인 Mutation 동작 전에 먼저 동작하는 함수, Optimistic update 적용할 때 유용
  • 나머진 특별히 설명할 거 없이 useQuery랑 비슷합니다. (오히려 Option이 더 적어요!)

3. Query Invalidation

간단히 queryClient를 통해 invalidate 메소드를 호출하면 끝이다.

// Invalidate every query in the cache
queryClient.invalidateQueries()
// Invalidate every query with a key that starts with 'todos'
queryClient.invalidateQueries('todos')

이러면 해당 Key를 가진 query는 stale 취급되고, 현재 rendering 되고 있는 query들은 백그라운드에서 refetch 됩니다.

React Query

출처: 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

profile
프론트엔드 개발자입니다.

0개의 댓글