React Query와 상태관리 (1)

8069 단어 Reactreact-queryReact

2월 우아한테크세미나 강의를 듣고 작성한 글입니다.


상태란?

주어진 시간에 대해 시스템을 나타내는 것으로 언제든지 변경될 수 있음
즉 문자열, 배열, 객체 등의 형태로 응용 프로그램에 저장된 데이터

  • 개발자 입장에선 관리해야하는 데이터들 !

모던 웹프론트엔드 개발

UI/UX의 중요성과 함께 프로덕트 규모가 많이 커지고 FE에서 수행하는 역할이 늘어남. 관리하는 상태가 많아짐. 상태관리의 필요성이 중요해졌다.

상태 관리는?

  • 상태를 관리하는 방법에 대한 것 -> 프로덕트가 커짐에 따라 어려움도 커짐
  • 상태들은 시간에 따라 변화함
  • React에선 단방향 바인딩이므로 Props Drilling 이슈도 존재
  • Redux와 MobX 같은 라이브러리를 활용해 해결하기도 함

상태관리 영역이 서버값을 저장하는데까지 확장

  • API 통신 관련 코드가 모두 Store에?
  • 또, 반복되는 isFetching, isError 등 API 관련 상태
  • 또또, 반복되는 비슷한 구조의 API 통신 코드

상태를 두 가지로 나누어 봅시다

Client StateServer 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을 관리한다.
// string 형태
useQuery('todos', ...) // queryKey === ['todos']

// Array 형태
useQuery(['todos', 5], ...) // queryKey === ['todos', 5]
useQuery(['todos', 5, { preview: true }], ...) // queryKey === ['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 : 신선하지 않은, 즉 상한 데이터

좋은 웹페이지 즐겨찾기