第162章:TanStack Query の導入と useQuery
この章のゴール🎯
- TanStack Query(旧 React Query)をプロジェクトに入れる
- アプリ全体に
QueryClientProviderを設定する useQueryで「ロード中/成功/失敗」をキレイに分けて表示できるようになる✨ (公式の基本形はuseQuery({ queryKey, queryFn })だよ〜!)(tanstack.com)
まず、TanStack Queryって何がうれしいの?😊📦
**サーバーから取ってくるデータ(= server state)**って、手作業だとこうなりがち👇
- ロード中の表示どうする?⏳
- エラーの表示どうする?🥺
- 何回も同じAPI叩いちゃう…💸
- 画面戻ったらまた取り直し…🙃
TanStack Queryはそれを「いい感じに」まとめて面倒見てくれるライブラリだよ✨(tanstack.com)
図でイメージ🌈(キャッシュが主役!)
1) インストールする(Windowsでも同じだよ🪟)
プロジェクトのフォルダで👇
npm i @tanstack/react-query
公式のインストール方法だよ✅(tanstack.com)
2) QueryClientProvider をアプリ全体にセットする🧠🧩
これを忘れると 「QueryClientが無いよ!」 って怒られます🥺(あるある)
src/main.tsx をこうする👇
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
const queryClient = new QueryClient()
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</React.StrictMode>,
)
「アプリを QueryClientProvider で囲む」のが基本形だよ✅(tanstack.com)
3) useQuery の最小セットを覚える(これが第162章の核心🔥)
useQuery は基本 この2つが必須👇
queryKey:キャッシュの住所🏠(同じ住所なら同じデータを共有)queryFn:Promiseを返す関数(成功ならデータ、失敗なら throw)
公式も「最低これ!」って言ってるよ✅(tanstack.com)
しかも queryFn は 「必ず resolve か throw」(undefined返しちゃダメ)ってルールもあるよ⚠️(tanstack.com)
4) 実際に1本作ろう🍰(ユーザー一覧を取って表示)
(A) まず「取得する関数」を作る📡
src/api/users.ts
export type User = {
id: number
name: string
email: string
}
export async function fetchUsers(): Promise<User[]> {
const res = await fetch('https://jsonplaceholder.typicode.com/users')
if (!res.ok) {
throw new Error(`HTTP ${res.status}`)
}
const data: User[] = await res.json()
return data
}
ポイント👉
res.okチェックして、ダメならthrow🥺- 返す型を
Promise<User[]>にして、TypeScriptに勝たせる💪✨
(B) useQuery で呼び出す💡
src/components/UsersList.tsx
import { useQuery } from '@tanstack/react-query'
import { fetchUsers, type User } from '../api/users'
export function UsersList() {
const { data, isPending, isError, error, isFetching, refetch } = useQuery<User[], Error>({
queryKey: ['users'],
queryFn: fetchUsers,
})
if (isPending) {
return <p>読み込み中…⏳</p>
}
if (isError) {
return (
<div>
<p>エラーだよ…🥺</p>
<pre>{error.message}</pre>
<button onClick={() => refetch()}>もう一回やってみる🔁</button>
</div>
)
}
if (!data) {
return <p>データが空っぽ…🤔</p>
}
return (
<section>
<h2>ユーザー一覧👩💻</h2>
<button onClick={() => refetch()} disabled={isFetching}>
{isFetching ? '更新中…🔄' : '手動で更新🔁'}
</button>
<ul>
{data.map((u) => (
<li key={u.id}>
{u.name}({u.email})📮
</li>
))}
</ul>
</section>
)
}
ここで使ってる isPending / isError は v5で特に大事な考え方だよ✨(statusが pending になった流れ)(tanstack.com)
(isLoading もあるけど、意味が少し違うのでまずは isPending からでOK!)(tanstack.com)
(C) App に置く🏠
src/App.tsx
import { UsersList } from './components/UsersList'
function App() {
return (
<main>
<h1>TanStack Query デビュー🎉</h1>
<UsersList />
</main>
)
}
export default App
5) 状態のイメージ(ロード中/成功/失敗)🎢
TanStack Query的には「クエリは key と結びついた非同期データの依存関係」って感じだよ🧠(tanstack.com)
よくあるつまづき集(先回りで回避💣➡️✅)
-
画面が “No QueryClient set…” で落ちた 😭 →
QueryClientProviderでAppを囲むの忘れがち!(tanstack.com) -
ロード中の条件がわからない 🤯 → まずは
isPendingを見ればOK(「まだデータが無い」状態)(tanstack.com) -
fetchが失敗しても成功扱いっぽい… 🙃 →
fetchは HTTP 404/500 でも例外を投げないので、res.okを見てthrowしようね⚠️(tanstack.com)
ミニ練習✍️✨(5分でできる!)
queryKey: ['users']を['users', 'list']に変えてみる🏷️- URLを
https://jsonplaceholder.typicode.com/postsに変えて、Post型を作って表示してみる📝 refetch()ボタンを押したとき、isFetchingがどう変わるか観察👀🔄(次章のDevToolsがあるともっと楽しいよ!)
まとめ🎀(この章の合言葉)
useQuery({ queryKey, queryFn })でデータ取得が「型安全&ラク」になる✨(tanstack.com)queryFnは resolve か throw(undefined禁止)⚠️(tanstack.com)- 状態分岐はまず
isPending / isErrorでOK🙆♀️(tanstack.com)
次の 第163章 は DevTools で「キャッシュの裏側」を覗いてニヤニヤする回だよ😎🔍