【覚書】TanStackQuery(ReactQuery)v5でSuspenseを使う
概要
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 機能を使う場合、以下の選択肢が存在します。
-
useQuery
の Suspense モードを有効にして使う -
useSuspenseQuery
を使う
なにが違うのか?
-
型がちがう
- Suspenseモードを使用すると
data
の型がTData | undefined
になる -
useSuspenseQuery
を使用するとdata
の型がTData
になる
- Suspenseモードを使用すると
-
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があったので目を通してみたところ、おそらく、メンテナー側は「placeholderData
やenabled
オプションは Suspense 使うならそもそも必要ないよー」みたいなことを言ってるっぽいです。それに対して使用者側は、「いや、全然placeholderData
やenabled
使いたいときあるよー。useQuery
の Suspense モードの方が使い勝手が良いから今もこっち使ってるよー」と主張してるっぽいなーって感じです。(間違ってたらすみません)
ReactQuery 公式は、v4までは Suspense モードを推奨していたのですが、v5からは新しく公式に導入されたuseSuspenseQuery
の使用を推奨しています。[1:1]
自分の所感としては、「型の恩恵がよくわからない人間にとっては Suspense モードの方が、楽っちゃ楽なのかもね……?」って感じです。綺麗にカチカチッと書きたい人はv5を使用したら良いんじゃないでしょうか?
useSuspenseQuery の使い方
今回はそんな v5 のuseSuspenseQuery
を使います。と言っても簡単で、useQuery
をuseSuspenseQuery
に置き換えるだけです。
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
を用いて無限スクロールを実装してみました。
デモページで実際に動かせます。
-
現在のReactQuery v5 では
useSuspenseQuery
はReactQueryの標準機能ですが、v4までは Suspensive というライブラリをインストールすることでuseSuspenseQuery
を利用することができました(現在はインストール不要)。 ↩︎ ↩︎
Discussion