2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

こんにちは。アメリカ在住で独学エンジニアを目指している Taira です。
前回の Tanstack Query に続き、本日は fetch の際に使用できる useQuery についてです。
API からデータを取るとき、ローディングやエラー処理を毎回書くのは大変です。そこで、今回紹介するuseQueryを使うと、キャッシュ・リフェッチ・エラー処理まで一括管理できます。
今回は useQuery の活用法や私のディレクトリ構成まで載せておこうと思います


インストール

まずはライブラリを導入します。

npm i @tanstack/react-query
npm i -D @tanstack/react-query-devtools

アプリ全体を囲む設定

React アプリ全体を QueryClientProvider でラップして、どこからでも Query を使えるようにします。

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import App from './App';

const queryClient = new QueryClient();

export default function Root() {
  return (
    <QueryClientProvider client={queryClient}>
      <App />
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
}

📌 ReactQueryDevtools を入れておくと、キャッシュやフェッチ状態を GUI で確認できて便利。


useQuery の基本

import { useQuery } from '@tanstack/react-query';
import axios from 'axios';

const fetchStudents = async () => {
  const { data } = await axios.get('/api/students');
  return data;
};

export const Students = () => {
  const { data, isPending, error } = useQuery({
    queryKey: ['students'],
    queryFn: fetchStudents,
  });

  if (isPending) return <p>Loading...</p>;
  if (error) return <p>Error!</p>;

  return (
    <ul>
      {data.map((s: { id: number; name: string }) => (
        <li key={s.id}>{s.name}</li>
      ))}
    </ul>
  );
};
  • isLoading: 初回フェッチ時だけ true
  • isPending: フェッチ中は常に true

実務でのディレクトリ構成

現場では「機能ごとにまとめる」スタイルが多いです。

src/
  features/
    students/
      api/studentApi.ts          // API呼び出し
      queries/useStudentsQuery.ts // useQueryフック
      key.ts                     // queryKeyの定義

1. API 呼び出し(features/students/api/studentApi.ts)

import { api } from '@/lib/api';

export const fetchStudents = async () => {
  const { data } = await api.get('/students');
  return data;
};

2. queryKey の定義(features/students/key.ts)

export const studentKeys = {
  all: ['students'] as const,
  list: () => [...studentKeys.all, 'list'] as const,
  detail: (id: number) => [...studentKeys.all, 'detail', id] as const,
};

3. useQuery フック(features/students/queries/useStudentsQuery.ts)

import { useQuery } from '@tanstack/react-query';
import { fetchStudents } from '../api/studentApi';
import { studentKeys } from '../key';

export const useStudentsQuery = () =>
  useQuery({
    queryKey: studentKeys.list(),
    queryFn: fetchStudents,
  });

4. コンポーネントで利用(components/Students.tsx)

import { useStudentsQuery } from '@/features/students/queries/useStudentsQuery';

export const Students = () => {
  const { data, isPending, error } = useStudentsQuery();

  if (isPending) return <p>Loading...</p>;
  if (error) return <p>Error!</p>;

  return (
    <ul>
      {data?.map((s) => (
        <li key={s.id}>{s.name}</li>
      ))}
    </ul>
  );
};

まとめ

  • useQuery はサーバーからデータを取るための基本フック。
  • 状態フラグは isPending を使うのが最近の流れ。
  • 実務では features/配下に api, queries, key.ts をまとめる構成 が多い。
  • 最初に QueryClientProvider でアプリ全体を囲むのを忘れずに!

参考記事

とても分かりやすく Tanstack Query の概要を知る際に利用させていただきました。
なんとなく Tanstack Query いいなって思ったらぜひ以下リンクから詳細を見てみてください。
特に key.ts の書き方やdata,error,isPending という返却値以外に指定する値なども書いてあるので細かい制御をする際にためになると思います。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?