React-Query 맛보기

강재민·2023년 8월 16일
post-thumbnail

*출처 less of you

React-Query

    1. React Query는 React Application에서 서버 상태를 불러오고, 캐싱하며, 지속적으로 동기화하고 업데이트하는 작업을 도와주는 라이브러리입니다.
    1. 복잡하고 장황한 코드가 필요한 다른 데이터 불러오기 방식과 달리 React Component 내부에서 간단하고 직관적으로 API를 사용할 수 있습니다.
    1. 더 나아가 React Query에서 제공하는 캐싱, Window Focus Refetching 등 다양한 기능을 활용하여 API 요청과 관련된 번잡한 작업 없이 “핵심 로직”에 집중할 수 있습니다.

1.캐싱(Cashing)

*캐싱이란 특정 데이터의 복사본을 저장하여 이후 동일한 데이터의 재접근 속도를 높이는 것을 말한다!

React-Query는 캐싱을 통해 동일한 데이터에 대한 반복적인 비동기 데이터 호출을 방지하고, 이는 불필요한 API 콜을 줄여 서버에 대한 부하를 줄이는 좋은 결과를 가져온다.

만일 서버 데이터를 불러와 캐싱한 후, 실제 서버 데이터를 확인했을 때 서버 상에서 데이터의 상태가 변경되어있다면, 사용자는 실제 데이터가 아닌 변경 전의 데이터를 바라볼 수밖에 없게 된다. 이는 사용자에게 잘못된 정보를 보여주는 에러를 낳는다.

- Refetching

위와 같은 에러를 발생시키지 않는 좋은 캐싱 기능을 제공한다는 것은 결국 필요한 상황에 적절하게 데이터를 갱신해줄 수 있다는 말과 같다. 그럼 그런 상황은 언제일까?

    1. 화면을 보고 있을 때
    1. 페이지의 전환이 일어났을 때
    1. 페이지 전환 없이 이벤트가 발생해 데이터를 요청할 때
refetchOnWindowFocus, //default: true , 브라우저에 포커스가 들어온 경우
refetchOnMount, //default: true , 새로운 컴포넌트 마운트가 발생한 경우
refetchOnReconnect, //default: true , 네트워크 재연결이 발생한 경우
staleTime, //default: 0 , fresh → stale 상태로 변경되는 데 걸리는 시간이다.
cacheTime, //default: 5분 (60 * 5 * 1000) , cacheTime은 데이터가 inactive한 상태일 때 캐싱된 상태로 남아있는 시간이다.```

#### staleTime && cacheTime

**staleTime**
- fresh 상태일 때는 Refetch 트리거(위의 3가지 경우)가 발생해도 Refetch가 일어나지 않는다!
- 기본값이 0이므로 따로 설정해주지 않는다면 Refetch 트리거가 발생했을 때 무조건 Refetch가 발생한다!
**cacheTime**
- 특정 컴포넌트가 unmount(페이지 전환 등으로 화면에서 사라질 때) 되면 사용된 데이터는 inactive상태로 바뀌고, 이때 데이터는 cacheTime만큼 유지된다.
- cacheTime 이후 데이터는 가비지 콜렉터로 수집되어 메모리에서 해제된다.
- 만일 cacheTime이 지나지 않았는데 해당 데이터를 사용하는 컴포넌트가 다시 mount되면, 새로운 데이터를 fetch해오는 동안 캐싱된 데이터를 보여준다.
- 즉, 캐싱된 데이터를 계속 보여주는게 아니라 fetch하는 동안 **임시**로 보여준다는 것이다.

> ### useQuery
- 첫 번째 파라미터로 unique key를 포함한 배열이 들어간다. 이후 동일한 쿼리를 불러올 때 유용하게 사용된다.
- 첫 번째 파라미터에 들어가는 배열의 첫 요소는 unique key로 사용되고, 두 번째 요소부터는 query 함수 내부의 파라미터로 값들이 전달된다.
- 두 번째 파라미터로 실제 호출하고자 하는 비동기 함수가 들어간다. 이때 함수는 Promise를 반환하는 형태여야 한다.
최종 반환 값은 API의 성공, 실패 여부, 반환값을 포함한 객체이다.

시작하기

> $ npm i @tanstack/react-query
# or
$ pnpm add @tanstack/react-query
# or
$ yarn add @tanstack/react-query

import {
QueryClient,
QueryClientProvider,
useQuery,
} from '@tanstack/react-query'

const queryClient = new QueryClient()

export default function App() {
return (



)
}

function Example() {
const { isLoading, error, data } = useQuery({
queryKey: ['repoData'],
queryFn: () =>
fetch('https://api.github.com/repos/TanStack/query').then(
(res) => res.json(),
),
})

if (isLoading) return 'Loading...'

if (error) return 'An error has occurred: ' + error.message

// We can assume by this point that isSuccess === true
return (

<div>
  <h1>{data.name}</h1>
  <p>{data.description}</p>
  <strong>👀 {data.subscribers_count}</strong>{' '}
  <strong>✨ {data.stargazers_count}</strong>{' '}
  <strong>🍴 {data.forks_count}</strong>
</div>

)
}


useQuery 함수가 반환하는 객체는 
- isLoading 을 통해 로딩 여부를,
- error 를 통해 에러 발생 여부를, 
- data를 통해 성공 시 데이터를 반환할 수 있다.

status 상태도 사용이 가능하다.

function Todos() {
const { status, data, error } = useQuery({
queryKey: ['todos'],
queryFn: fetchTodoList,
})

if (status === 'loading') {
return Loading...
}

if (status === 'error') {
return Error: {error.message}
}

// also status === 'success', but "else" logic works, too
return (

<ul>
  {data.map((todo) => (
    <li key={todo.id}>{todo.title}</li>
  ))}
</ul>

)
}


status 필드를 사용하면 result 객체에 추가적으로 fetchStatus 프로퍼티를 사용할 수 있다.

- fetchStatus === 'fetching' - The query is currently fetching.
- fetchStatus === 'paused' - The query wanted to fetch, but it is paused.
- fetchStatus === 'idle' - The query is not doing anything at the moment.

> ### useMutation

- PUT, UPDATE, DELETE 와 같이 값을 변경할 때 사용하는 API다. 반환값은 useQuery와 동일하다.

function App() {
const mutation = useMutation({
mutationFn: (newTodo) => {
return axios.post('/todos', newTodo)
},
})

return (

<div>
  {mutation.isLoading ? (
    'Adding todo...'
  ) : (
    <>
      {mutation.isError ? (
        <div>An error occurred: {mutation.error.message}</div>
      ) : null}

      {mutation.isSuccess ? <div>Todo added!</div> : null}

      <button
        onClick={() => {
          mutation.mutate({ id: new Date(), title: 'Do Laundry' })
        }}
      >
        Create Todo
      </button>
    </>
  )}
</div>

)
}

- 반환값은 useQuery와 동일하지만, 처음 사용 시에 post 비동기 함수를 넣어주었다. 이때 useMutation의 첫 번째 파라미터에 비동기 함수가 들어가고, 두 번째 인자로 상황 별 분기 설정이 들어간다는 점이 차이이다.

- 실제 사용 시에는 mutation.mutate 메서드를 사용하고, 첫 번째 인자로 API 호출 시에 전달해주어야하는 데이터를 넣어주면 된다.

profile
말많은 개발자의 111강

0개의 댓글