React Query - React でリクエストを行う究極のガイド

React自体にはサーバーからデータをフェッチする方法に関しての指針はありません。

よく使われるのはFetchAPIとAxiosライブラリです。

間違ったアプローチ1: Fetch API 🎣

これはブラウザのFetch APIを使う一番基本的なアプローチです。

コンポーネントがマウントされたときにuseEffectフックを使って呼び出され、レスポンスはuseStateで管理されます。しかし、これは優れた開発者やベストな開発者が推奨する方法ではありません。

FetchAPIが良くない理由は以下のとおりです:

  • 簡単なタスクにたくさんのコードが必要です。
  • 開発者の経験をとても悪くする有用な機能がない。

間違ったアプローチ2: Axios 🪓

Axiosライブラリは上記のコードを少し簡単にしますが、素晴らしい開発者体験に必要ないくつかの機能がまだ足りません。

フェッチのためのコードを抽象化しますが、以下を助けません:

  • キャッシング。
  • エラーやローディングなどのデータステート。
  • まだtry-catch地獄があります。

では、上記の2つの魔法のような方法は間違っているので、正しい方法は何でしょうか。

React Query - サーバーからデータをフェッチ、キャッシュ、同期する方法を簡略化するライブラリ

はい、上記の2つは同じものです。

React QueryまたはTanstack Queryが実際に何をし、何であるか見てみましょう。

ただのデータフェッチライブラリではありません

React Queryが提供するのは、どのデータを欲しいかを記述し、そのデータをフェッチする能力だけではなく、そのサーバーデータのキャッシュ🧠も含まれています。

これは、同じuseQueryフックを複数のコンポーネントで使用でき、一度だけデータをフェッチして、その後はキャッシュからデータを返すことを意味します。

理論はもううんざり、コードを見せて ⌨

それでは、セットアップの方法と、React Queryが素晴らしいと感じるいくつかのユースケースを見てみましょう。

セットアップ(退屈な部分)

まず最初に、ReactJSまたはNextJSでプロジェクトがセットアップされている必要があります。
私はLynkit🔗プロジェクトでReact Queryを使用します。

プロジェクトにReact Queryを追加するには、次のコマンドを使用します:

npm i @tanstack/react-query

もしReduxContextAPIを使ったことがあるなら、使用する部分すべてにクライアントを利用可能にする必要があります。

これを行う最も簡単な方法は、アプリケーションの部分をclient-providerでラッピングすることですが、この場合はQueryClientProviderと呼ばれます。

ライブラリのすべての機能を処理するクライアントも作成する必要があります。

[!重要]
クライアントはこのケースでのReact Queryのベースクラスのインスタンスにすぎません。使用したい機能すべてを扱います。

私のプロジェクト(そして大抵のケースで)、AppのすべてのスコープからQueryClientにアクセスしたいので、それを全体にラップします。

import {
  QueryClient,
  QueryClientProvider,
} from '@tanstack/react-query'

const queryClient = new QueryClient()

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </QueryClientProvider>
  </React.StrictMode>
);

これでReact Queryのセットアップが完了し、そのさまざまなユースケースを見る時間です。

データフェッチ

GETリクエストを行うときは、React Queryライブラリが提供するuseQueryフックを使います。

注意:もしここでフックが理解できないなら、ここで一時停止して、Ayush Vermaによるこちらの記事を見てください:Hooks : プレーンな英語でのJS

では、useQueryフックについて。
クエリとは、基本的にはデータソースに関連した非同期リクエストです。そして非同期リクエストはJavaScriptではプロミスで処理されます。

したがって、useQueryフックはpending, fulfilled, rejectedの状態を監視するクエリにサブスクライブして、それに基づいて状態を返すために使われます。

たくさんの専門用語ですか?同意します。ですので、こちらに図解を用意しました:

フックは主に2つのパラメーターを取ります:

  • クエリのユニークなキー
  • プロミスを返す関数で、そのプロミスは:
    • データを解決する、もしくは
    • エラーを投げます

提供されたユニークなキーは内部でクエリのリフェッチing、キャッシュ、共有を行うために使用されます。

Lynkitでログイン済みユーザーデータを取得する例を見てみましょう。

Axios.get()を使用した実際のデータフェッチ

はい、データのフェッチにはAxiosを使用しますが、直接ではありません。
データを取得する関数を定義し、Userキーにクエリ関数として追加します。

したがって、Userデータを使用したいときはいつでも、UseQueryフックを使用してユーザーデータを取得できます:

  • クエリキャッシュに見つかった場合、そこからデータを返します。
  • それ以外の場合、以下の関数を呼び出します:
export const getUserData = async(): Promise<ProfileData> => {
    try {
      const response: AxiosResponse = await axios.get("http://localhost:3003/user", {
        headers: {
          "Content-Type": "application/json",
        },
        withCredentials: true,
      });
      const {status, data} = response;
      console.log(data)
      if(status !== 200 || !data.user){
        ...
        return nullUser;
      }
      return data.user as ProfileData;

    } catch (error) {
      console.log(error);
      throw new Error("Data Fetching Failed")
    }
}

UseQueryフックの使用方法は以下の通りです:

const {data, isError, isLoading} = useQuery<ProfileData>(
    {
      queryKey: ["user"],
      queryFn: getUserData,
      notifyOnChangeProps: ['data', 'error'],
      refetchOnWindowFocus: false
    }
)

上記は以下の手順で動作します:
ステップ1:渡されたクエリキーを読みます。この場合は["user"]です。
ステップ2:クエリキーがQuery Cacheにあるかチェックし、存在する場合は返します。
ステップ3:キャッシュにデータが存在しない場合、queryFnプロパティに渡された関数を呼び出します。

📌 useQueryフックはget ↩リクエスト専用で、他のリクエストにはuseMutationフックと mutateメソッドを使用します。

クエリの無効化 ❗📛

アクションが発生したときにデータを再フェッチしたい場合があります。
React Queryは、client.invalidateQueries()メソッドを提供して、それを行う方法も提供します。

再フェッチしたい同じqueryKeyを渡す必要があります。QueryClientはそのデータが無効になると自動的にデータを再フェッチします。

const queryClient = useQueryClient();
queryClient.invalidateQueries(["user"]);

この時点でキャッシュされていたユーザーデータが削除され、APIまたはサーバーから新しいデータが再び取得されます。

上記は2つの条件で使用されます:

  • ユーザー名やパスワードやイメージなどの一部を追加、編集、削除することによってデータが更新された場合。
  • ログアウト ❌ユーザー。

この時点で高度なクエリに基づくアプリケーションを開発する準備が整いました。

より詳細で完全な説明については、@tkdodoのプロファイルやComplete Tanstack Docs 💡をチェックしてください。

また、私の前のブログBun - 最速のJavascriptランタイム ⚡もご覧ください。

こちらの記事はdev.toの良い記事を日本人向けに翻訳しています。
https://dev.to/thevinitgupta/react-query-the-definitive-guide-to-making-requests-in-react-l92