1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

TanStack Queryについてまとめてみた

Last updated at Posted at 2024-05-30

viviONグループでは、DLsiteやcomipoなど、二次元コンテンツを世の中に届けるためのサービスを運営しています。
ともに働く仲間を募集していますので、興味のある方はこちらまで。

🔰 はじめに

Reactのデータフェッチライブラリ色々あるけど何がいいんだろう🤔と思って調べていた時に、TanStack Query(旧React Query)を勧められたので、備忘も兼ねてまとめてみました!

🚀 TanStack Queryとは

  • TanStack Queryとは、データの非同期取得及び更新・状態管理・キャッシュの機能を内包しているライブラリ
  • React/Solid/Vue/Svelteなど殆どのフレームワークで使える(React Nativeも対応しているらしい)
  • APIサーバからのレスポンスを状態管理することができる
  • SWRよりもキャッシュの管理に関して細かく設定できる利点がある

🔬 実装例

📝 データの取得(GET)

useQueryというフックを使用することで、データのフェッチを行うことができます。

import {
  useQuery,
  useMutation,
  useQueryClient,
  QueryClient,
  QueryClientProvider,
} from '@tanstack/react-query'
import { getTodos, postTodo } from '../my-api'

// QueryClientのインスタンスを作成し、QueryClientProviderに渡す(QueryClient自体はキャッシュで使用する)
const queryClient = new QueryClient()
function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <Todos />
    </QueryClientProvider>
  )
}
    
function Todos() {
  // useQueryでデータを取得
  const { isLoading, isError, data, error } = useQuery({
    // queryKeyでキーを指定する。キャッシュ管理などに使用する
    queryKey: ['todos'],
    // queryFnでデータ取得用の関数を入れる
    queryFn: async() => {
      const { data } = await axios.get(
        'https//example.api/todos'
      )
      return data
    },
    // staleTimeにキャッシュが古くなるまでの時間を指定できる。デフォルトでは0(即古いとみなす)
    staleTime: 1000,
    // ウィンドウにフォーカスが当たったら再取得なども可能
    refetchOnWindowFocus: true,
  })

  // isLoadingでローディング状態を取得
  if (isLoading) {
    return <LoadingSpinner />
  }

  // isErrorでエラーかを取得
  if (isError) {
    showErrorDialog()
  }

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

render(<App />, document.getElementById('root'))

🚨v5だと、Suspense利用時にuseQueryが使用できないので注意。 useSuspenseQuery()useSuspenseInfiniteQuery()useSuspenseQueries()
を必要に応じて使用していく。

📝 データの更新(POST)

useMutationというフックを使用することで、データの更新を行うことができます。

import {
  useQuery,
  useMutation,
  useQueryClient,
  QueryClient,
  QueryClientProvider,
} from '@tanstack/react-query'
import { getTodos, postTodo } from '../my-api'

const queryClient = new QueryClient()
function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <Todos />
    </QueryClientProvider>
  )
}

function Todos() {
  const queryClient = useQueryClient()
  // useQueryでデータを取得
  const query = useQuery({
    queryKey: ['todos'],
    queryFn: async() => {
      const { data } = await axios.get(
        'https//example.api/todos'
      )
      return data
    },
  })
  // useMutationでデータの更新を行なう
  const mutation = useMutation({
    // mutationFnにデータ更新用の関数を入れる
    mutationFn: async({id, title}) => {
      const { data } = await axios.post(
      'https//example.api/todos',
        {
          id,
          title
        }
      )
    },
    // onSuccessで更新成功時の処理を記載することができる
    onSuccess: (result) => {
      // queryClient.setQueryDataを使用することでキャッシュの値を更新することができる
      queryClient.setQueryData(['todos'], prev => [...prev, result])
    }
  })

  return (
    <div>
      <ul>
        {query.data?.map((todo) => (
          <li key={todo.id}>{todo.title}</li>
        ))}
      </ul>
      <button
        onClick={() => {
          mutation.mutate({
            id: 1,
            title: 'タイトル',
          })
        }}
      >
        Add Todo
      </button>
    </div>
  )
}
render(<App />, document.getElementById('root'))

📈 TanStack Queryを使用することによるメリット

以前とあるプロジェクトにて、SWRを使用してデータフェッチの部分を開発していたのですが、SWRと比較するとキャッシュ部分に関してかなり細かいところまで詰めることができるなと言った印象です。

👍 useQueryのオプションで、StaleTimeCacheTimeを設定することができるため、ページに応じて、適切なキャッシュ時間を細かく設定することができる

👍 更新頻度が高いページ(リアルタイムにデータの更新が必要なものなど)はStaleTimeを0にして、更新頻度が低いページ(CMSで管理しているものなど)やAPIの処理が重いページはStaleTimeを大きめに設定するなど、適切なキャッシュ設定をすることで、サイト全体のパフォーマンスを高めることができる

👍 useQueryのオプションが便利
enabled
enabledがtrueの時のみクエリを実行する
例えば認証完了時にのみ実行したいなど、特定のstateの状態を監視して実行するか分岐させたい時に使える

const { isLoading, isError, data, error } = useQuery({
  queryKey: ['todos'],
  queryFn: getTodos
  // isAuthenticatedがtrueの時のみクエリを実行
  enabled: isAuthenticated
})

select
selectをつけることで、取得したデータのfilteringをすることができる

const {data} = useQuery({
  queryKey: ['todos'],
  queryFn: getTodos,
  // isCheckedがtrueの要素のみ取得している
  select: (data) => data.map((todo) => todo.isChecked)
)

💬 所感

個人的には、以下のような条件で適宜プロジェクトに合わせて導入するのが望ましいかと思いました!!
プロジェクト自体がミニマムで、データフェッチがメインでキャッシュはそれほど重視しない => SWR
データフェッチに加えて、ページのキャッシュ部分をもっと突き詰めたい => TanStack Query

🔗 参考文献

🌈 一緒に二次元業界を盛り上げていきませんか?

株式会社viviONでは、フロントエンドエンジニアを募集しています。

また、フロントエンドエンジニアに限らず、バックエンド・SRE・スマホアプリなど様々なエンジニア職を募集していますので、ぜひ採用情報をご覧ください。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?