React Queryでボタンクリック時にデータを取得する方法
問題
React QueryのuseQuery
フックは、デフォルトではコンポーネントのマウント時に自動的にデータ取得を実行します。しかし、ユーザーの操作(ボタンクリックなど)をトリガーとしてデータ取得を開始したい場合があります。
解決策
React Queryには、手動でのデータ取得を実現するためのいくつかの方法があります。
方法1: enabled: false
とrefetch
の使用(推奨)
最も一般的な方法は、useQuery
のenabled
オプションをfalse
に設定し、refetch
関数を使用して手動でデータ取得をトリガーする方法です。
import { useQuery } from '@tanstack/react-query';
const fetchData = async () => {
const response = await fetch('/api/data');
return response.json();
};
function DataComponent() {
const { data, isLoading, isError, error, refetch } = useQuery({
queryKey: ['myData'],
queryFn: fetchData,
enabled: false, // 自動実行を無効化
});
const handleClick = () => {
refetch(); // 手動でデータ取得を実行
};
return (
<div>
<button onClick={handleClick} disabled={isLoading}>
{isLoading ? '読み込み中...' : 'データ取得'}
</button>
{isError && <p>エラー: {error.message}</p>}
{data && <pre>{JSON.stringify(data, null, 2)}</pre>}
</div>
);
}
TIP
refetch
関数は以下のオプションをサポートしています:
throwOnError
: エラー時に例外をスローするかどうかcancelRefetch
: 実行中のリクエストをキャンセルするかどうか(デフォルト: true)
方法2: queryClient.fetchQuery
の使用
状況によっては、クエリクライアントのfetchQuery
メソッドを直接使用する方法も有効です。
import { useQueryClient } from '@tanstack/react-query';
import { useState } from 'react';
function DataComponent() {
const queryClient = useQueryClient();
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const handleClick = async () => {
try {
setIsLoading(true);
const result = await queryClient.fetchQuery({
queryKey: ['myData'],
queryFn: fetchData,
});
setData(result);
} catch (error) {
console.error('データ取得に失敗しました', error);
} finally {
setIsLoading(false);
}
};
return (
<div>
<button onClick={handleClick} disabled={isLoading}>
{isLoading ? '読み込み中...' : 'データ取得'}
</button>
{data && <pre>{JSON.stringify(data, null, 2)}</pre>}
</div>
);
}
WARNING
queryClient.fetchQuery
はキャッシュを考慮せずに常に新しいデータを取得します。キャッシュの利点を活かしたい場合は、refetch
を使用することを推奨します。
方法3: 動的なクエリキーを使用した方法
特定のパラメータに基づいてクエリを実行したい場合は、動的なクエリキーを使用する方法もあります。
import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
function UserComponent() {
const [userId, setUserId] = useState(null);
const { data, isLoading } = useQuery({
queryKey: ['user', userId],
queryFn: () => fetchUser(userId),
enabled: !!userId, // userIdがセットされたときのみ実行
});
const handleClick = (id) => {
setUserId(id);
};
return (
<div>
<button onClick={() => handleClick(1)}>
ユーザー1を取得
</button>
<button onClick={() => handleClick(2)}>
ユーザー2を取得
</button>
{isLoading && <p>読み込み中...</p>}
{data && <p>ユーザー名: {data.name}</p>}
</div>
);
}
ベストプラクティス
エラーハンドリング
const { data, isLoading, isError, error, refetch } = useQuery({
queryKey: ['myData'],
queryFn: fetchData,
enabled: false,
retry: 1, // 失敗時の再試行回数
});
const handleClick = () => {
refetch({
throwOnError: true, // エラー時に例外をスロー
cancelRefetch: true // 実行中のリクエストをキャンセル
}).catch(error => {
// エラー処理
console.error('データ取得エラー:', error);
});
};
キャッシュの無効化と再取得
ミューテーション後にデータを再取得する場合:
import { useMutation, useQueryClient } from '@tanstack/react-query';
function UpdateComponent() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: updateData,
onSuccess: () => {
// ミューテーション成功後、関連データを再取得
queryClient.invalidateQueries({
queryKey: ['myData']
});
},
});
const handleUpdate = () => {
mutation.mutate({ id: 1, name: '新しい値' });
};
return (
<button onClick={handleUpdate} disabled={mutation.isLoading}>
データを更新
</button>
);
}
まとめ
React Queryでボタンクリック時にデータを取得するには、主に以下の方法があります:
enabled: false
+refetch
: 最も一般的で推奨される方法queryClient.fetchQuery
: より細かい制御が必要な場合- 動的クエリキー: パラメータに基づくクエリ実行に適している
どの方法を選択するかは、具体的なユースケースとキャッシュの扱い方によって決定します。ほとんどの場合、enabled: false
とrefetch
を組み合わせた方法が最も適しています。