🏝️

【覚書】TanStackQuery(ReactQuery)v5でSuspenseを使う

2024/06/18に公開

概要

ReactQuery v5で Suspense を使う際に、ReactQuery のバージョンの違いについてつまずいたので、その際に調べたことなどを書き残します。

また、当記事で想定している使用技術は Vite、 React、 ReactQuery のみで、 Next.js などの React フレームワークの使用は想定していません。

React の Suspense 機能について

React の標準機能に Suspense という機能があります。
具体的には以下のような条件分岐を

if (status === "pending") {
  return <Loading />
}
return <Content />

以下のように書くことができる、という機能です。

<Suspense fallback={<Loading />}>
  <Content />
</Suspense>

ReactQuery で Suspense を使う

早速、 ReactQuery で Suspense を使ってみます。

まず、 ReactQuery のデータフェッチングと一緒に Suspense 機能を使う場合、以下の選択肢が存在します。

  1. useQueryの Suspense モードを有効にして使う
  2. useSuspenseQueryを使う

なにが違うのか?

  • 型がちがう

    • Suspenseモードを使用するとdataの型がTData | undefinedになる
    • useSuspenseQueryを使用するとdataの型がTDataになる
  • useSuspenseQueryを使用するとplaceholderDataオプションやenabledオプションが使用できない

まず「型がちがう」についてですが、Suspensive[1]docsに、以下のようなことが書いてあります。

// SuspenseモードでSuspenseを使う場合

function App() {
  const { data } = useQuery({
    queryKey: 'exampleKey',
    queryFn: fetchExampleData,
    suspense: true,  // Suspenseモードを有効にする
  })

  return (
    <p>{data}</p> // undefined
  )
}
// {data} を <Suspense> で囲ったとしても、{data} の型は TData | undefined となるらしい
// useSuspenseQueryを使う場合

function App() {
  const { data } = useSuspenseQuery({
    queryKey: 'exampleKey',
    queryFn: fetchExampleData,
  })

  return (
    <p>{data}</p> // TData
  )
}

// {data} を <Suspense> で囲まなくても、 undefined を返さないらしい

TypeScriptを使用していないからなのか、これがどれだけ良いことなのか自分にはわかりませんが 😭、なんだかとても良いことらしいです。😊

次に「useSuspenseQueryを使用するとplaceholderDataオプションとenabledオプションが使用できない」についてですが、これに関しても、実はあまりよくわからないです。
TanStackQueryのGitHubで、このことについてのDiscussionsがあったので目を通してみたところ、おそらく、メンテナー側は「placeholderDataenabledオプションは Suspense 使うならそもそも必要ないよー」みたいなことを言ってるっぽいです。それに対して使用者側は、「いや、全然placeholderDataenabled使いたいときあるよー。useQueryの Suspense モードの方が使い勝手が良いから今もこっち使ってるよー」と主張してるっぽいなーって感じです。(間違ってたらすみません)

ReactQuery 公式は、v4までは Suspense モードを推奨していたのですが、v5からは新しく公式に導入されたuseSuspenseQueryの使用を推奨しています。[1:1]
自分の所感としては、「型の恩恵がよくわからない人間にとっては Suspense モードの方が、楽っちゃ楽なのかもね……?」って感じです。綺麗にカチカチッと書きたい人はv5を使用したら良いんじゃないでしょうか?

useSuspenseQuery の使い方

今回はそんな v5 のuseSuspenseQueryを使います。と言っても簡単で、useQueryuseSuspenseQueryに置き換えるだけです。

import { Suspense } from 'react'
import { useSuspenseInfiniteQuery } from '@tanstack/react-query'

function App() {
  return (
    <Suspense fallback={<p>Loading...</p>}>
        <Data />
    </Suspense>
  )
}

function Data() {
  const { data } = useSuspenseQuery({
    queryKey: 'exampleKey',
    queryFn: fetchExampleData,
  })

  return (
    <p>{data}</p>
  )
}

こんな感じでわりと簡単にuseQueryからuseSuspenseQueryに移行ができます。
同様にuseQueriesに対応したuseSuspenseQueriesや、useInfiniteQueryに対応したuseSuspenseInfiniteQueryも存在します。

下記のリポジトリでuseSuspenseInfiniteQueryを用いて無限スクロールを実装してみました。
https://github.com/kagomen/react-query-practice
デモページで実際に動かせます。

脚注
  1. 現在のReactQuery v5 ではuseSuspenseQueryはReactQueryの標準機能ですが、v4までは Suspensive というライブラリをインストールすることでuseSuspenseQuery を利用することができました(現在はインストール不要)。 ↩︎ ↩︎

Discussion