Skip to content

React Queryでボタンクリック時にデータを取得する方法

問題

React QueryのuseQueryフックは、デフォルトではコンポーネントのマウント時に自動的にデータ取得を実行します。しかし、ユーザーの操作(ボタンクリックなど)をトリガーとしてデータ取得を開始したい場合があります。

解決策

React Queryには、手動でのデータ取得を実現するためのいくつかの方法があります。

方法1: enabled: falserefetchの使用(推奨)

最も一般的な方法は、useQueryenabledオプションをfalseに設定し、refetch関数を使用して手動でデータ取得をトリガーする方法です。

js
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メソッドを直接使用する方法も有効です。

js
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: 動的なクエリキーを使用した方法

特定のパラメータに基づいてクエリを実行したい場合は、動的なクエリキーを使用する方法もあります。

js
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>
  );
}

ベストプラクティス

エラーハンドリング

js
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);
  });
};

キャッシュの無効化と再取得

ミューテーション後にデータを再取得する場合:

js
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でボタンクリック時にデータを取得するには、主に以下の方法があります:

  1. enabled: false + refetch: 最も一般的で推奨される方法
  2. queryClient.fetchQuery: より細かい制御が必要な場合
  3. 動的クエリキー: パラメータに基づくクエリ実行に適している

どの方法を選択するかは、具体的なユースケースとキャッシュの扱い方によって決定します。ほとんどの場合、enabled: falserefetchを組み合わせた方法が最も適しています。