Tanstack Query

BlackBean·2024년 11월 9일

web

목록 보기
4/5

1. Tanstack 이 뭐야?

JS/TS 에서 사용할 수 있는 비동기 상태 관리자

tanstack query 를 이용해 fetching, caching, synchronizing, updating server state 를 손쉽게 할 수 있다.

2. 왜 써?

비동기적으로 동작하는 서버의 상태를 브라우저에서 보여줄 때, tanstack query 를 이용하면 서버의 상태를 손쉽게 업데이트 할 수 있다.

예를 들어 유저의 할일 목록을 추가했다면, react-query 를 통해 서버의 상태를 동기화 해주어 유저가 바로 변경된 목록을 확인할 수 있다.

3. 어떻게 써?

useQuery 와 useInfiniteQuery 를 통해 받은 Query instance 는 기본적으로 캐시된 데이터는 오래된 데이터로 간주한다.

오래된 쿼리를 자동으로 패치하려면

  • 새로운 쿼리 인스턴스가 생성되거나

  • 윈도우가 다시 포커스되거나

  • 네트워크가 다시 접속되거나

  • 쿼리 옵션에 refetch interval 을 설정하면 된다.

    active instance 가 없는 쿼리결과는 inactive 로 레이블되고, 나중에 다시 사용될 수 있도록 캐시에 남는다.

기본적으로 inactive query 는 5분뒤에 garbage collect 된다.

1. Query 란?

쿼리는 서버에서 데이터를 업데이트 (구독) 할 때 사용한다.

쿼리는 고유키에 연결된 비동기 데이터 소스에 대한 선언적 종속성.
쿼리는 서버에서 데이터를 패치하기 위해 Promise 기반의 method 를 사용할 수 있다. method 가 서버의 데이터를 수정하는 경우 mutations 을 사용하는 것이 좋다.

컴포넌트나 훅을 쿼리해서 추적(구독)하려면 useQuery를 사용하자.

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

function App() {
  const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodoList })
}
  • query key : 내부적으로 refetching, caching, sharing queries 를 할 때 사용할 키. 기본적으로 tanstack은 쿼리 키에 따라 쿼리 캐싱을 관리함. 쿼리키는 배열이어야 함.
    • 간단한 쿼리키 : 상수값을 가진 배열
      // A list of todos
      useQuery({ queryKey: ['todos'], ... })
      
      // Something else, whatever!
      useQuery({ queryKey: ['something', 'special'], ... })
    • 변수가 있는 쿼리키 : 데이터를 고유하게 설명하는 데 더 많은 정보가 필요한 경우
      계층을 표현할 때는 배열의 요소로 넘기고, 추가적인 설명이 필요할 땐 마지막에 객체를 전달
      ```jsx
      // An individual todo
      useQuery({ queryKey: ['todo', 5], ... })
      
      // An individual todo in a "preview" format
      useQuery({ queryKey: ['todo', 5, { preview: true }], ...})
      
      // A list of todos that are "done"
      useQuery({ queryKey: ['todos', { type: 'done' }], ... })
      ```
  • queryFn: fetch함수 (데이터를 받거나 에러를 처리하는 함수)

  • result: 쿼리 결과 및 쿼리 상태를 확인할 수 있는 object

    const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodoList })
    • data, error, isFetching 등.
    • status : data 가 있나 없나? (isPending, isError, isSuccess)
    • fetchStatus: 지금 fetch중인가? (fetching, paused, idle)
  • 사용예제

    function Todos() {
      const { isPending, isError, data, error } = useQuery({
        queryKey: ['todos'],
        queryFn: fetchTodoList,
      })
    
      if (isPending) {
        return <span>Loading...</span>
      }
    
      if (isError) {
        return <span>Error: {error.message}</span>
      }
    
      // We can assume by this point that `isSuccess === true`
      return (
        <ul>
          {data.map((todo) => (
            <li key={todo.id}>{todo.title}</li>
          ))}
        </ul>
      )
    }

2. Mutation ?

mutation은 서버에 데이터를 create/update/delete 를 할 때 사용한다. 이 때는 useMutation 훅을 사용하자
useMutation 을 통하면 success, error, settled callback 을 처리할 수 있고, retry횟수도 지정 가능하다.

3. Query Invalidation ?

현재 query 에 있는 데이터가 stale 데이터가 되기를 기다리지 않고 바로 업데이트를 해야할 때가 있다. 특히 유저가 특정 작업을 완료해서 현재 저장된 데이터가 out-dated 데이터가 된 경우이다. 이 때를 위해 QueryClient 는 InvalidateQueries method 를 지원하여 현재 쿼리가 stale이라 표기하고 refetch하도록 한다.

- invalidateQueries 에 queryKey 를 지정하여 해당 키에 대한 query 들을 무효화시킬 수 있다.

```jsx
import { useQuery, useQueryClient } from '@tanstack/react-query'

// Get QueryClient from the context
const queryClient = useQueryClient()

queryClient.invalidateQueries({ queryKey: ['todos'] })

// Both queries below will be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})
const todoListQuery = useQuery({
  queryKey: ['todos', { page: 1 }],
  queryFn: fetchTodoList,
})
```

- predicate 함수를 이용하면 key 에 대한 정보를 활용하여 무효화 할 키를 추출할 수 있다.

```jsx
queryClient.invalidateQueries({
  predicate: (query) =>
    query.queryKey[0] === 'todos' && query.queryKey[1]?.version >= 10,
})

// The query below will be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 20 }],
  queryFn: fetchTodoList,
})

// The query below will be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 10 }],
  queryFn: fetchTodoList,
})

// However, the following query below will NOT be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 5 }],
  queryFn: fetchTodoList,
})
```
profile
React, React-native, Web developer

0개의 댓글