TanStack Query(旧React Query)について整理してみた

この記事は ウェブクルー Advent Calendar 2022 5日目の記事です。
昨日は @wc-nakagomi さんの「 【タイポ好きデザイナー厳選】 本当に使える Adobe Fonts 18選！」でした。

# はじめに

まずこちらのライブラリはSWRみたいな挙動(APIなどから取得したデータをクライアント側でキャッシュをしレンタリング最適化できる仕組み)を簡単に実現できるライブラリです。
TanStack Queryというのはv3まではReact Queryと呼ばれておりました。
v4以降でTanStack Queryというものに変更されました。挙動としてはほぼ変わらずTanStack Query(旧React Query)という解釈ですが、
TanStack QueryになってからはReact以外のVueやSolidのQueryも統合されたました。
TanStack Queryの大まかな機能としては下記かな？と思っております。
1. APIからデータを取得する際の記述量が少なく楽
2. APIから取得してデータをキャッシュに保存し、再フェッチせずともデータを参照できる

上記の中でも2のキャッシュを残して再フェッチせず済むというのが大きなメリットかなと思われます。
今回はそのTanStack Query(Reactで使用の場合)について少しまとめていきたいと思います。

## 初期設定
手順としては簡単で下記2つの手順で実装できます。

1.下記コマンドでインストール  
お察しの通りVueなどで使用したい場合は｀@tanstack/vue-query｀に変更していただければと。
```
npm i @tanstack/react-query
```

2.次に_app.jsでAPIのキャッシュデータを全ページで使えるよう設定していきます
```js:_app.js
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';

function App() {
  const queryClient = new QueryClient();

  return (
    <QueryClientProvider client={queryClient}>
       //略
       <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
}

```
プログラム上にさらっと記載しました`ReactQueryDevtools`タグですが、これもTanstack Queryの機能の一つでデベロップツールとなります。
それによりどのようなデータがキャッシュされているか、データがどの状態(ここに関しては後程記載して行きます)なのかを目視で確認できます。(画像を参照)

![スクリーンショット 2022-11-18 9.19.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314264/09b4d8fd-fa8e-d78d-851e-65c00a2920f3.png)

こちらはデフォルトで`process.env.NODE_ENV === 'development'`という記述が`@tanstack/react-query`に入っているため開発環境でのみ表示される仕様になっております。
補足でオプションに設定されている`initialIsOpen={false}`を追加する事により初期表示で下記画像のアイコンだけになり、アイコンをクリックすると上記のようにデベロップツールが開かれるというようなものです。
![スクリーンショット 2022-11-18 9.19.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314264/39b35b9b-2414-5027-9488-a786428f97a3.png)


以上でTanStack Queryを使う準備が整いました。

## 記述の説明

```js:index.js

import { useQuery } from 'react-query';

const { data, isLoading, isError, error, status } = useQuery(
  'クエリキー',
  'クエリ関数',
  {
    cacheTime: 1000,
  }
);

```

よく使うパターンはざっと上記のようになるかなと思われます。
ここに関しては [ドキュメント](https://tanstack.com/query/v4/docs/reference/useQuery?from=reactQueryV3&original=https://react-query-v3.tanstack.com/reference/useQuery)を読んだ方がわかりやすいかなと？思われますが、ざっと説明します。

### 戻り値について
下記表のものをよく使うかなと思われます。
isLoadingに関しては、if文でクエリの試行が完了するまでデータ表示に関わる部分は表示せずに`<div>Loading....</div>`を表示させておくケースをよく見ますね。
```js:example.js
if(isLoading) return <div>Loading...</div>
```

| 戻り値    | 説明                                                                                  | 
| --------- | ------------------------------------------------------------------------------------- | 
| data      | 正常にクエリの試行できた際に返り値が入る部分。初期値はundefined                      | 
| isLoading | クエリの試行がまだ完了していない場合にtrueを返し、完了した場合はfalseを返す           | 
| isError   | クエリの試行でエラーが発生した場合にtrueを返し、エラー発生していない場合はfalseを返す | 
| error     | クエリの試行でエラーが発生した場合いにエラーコードがオブジェクト形式で返される。      | 
| status    | 現状クエリの試行がどの状態かを示したもの　例)`loading`,`error`,`success`              | 

### クエリキー
dataの値がある場合にそれを引っ張ってくるためのkeyみたいなものです。
下記のように配列に定数or変数を入れ設定できます。例1ですとtestという名のクエリキーを設定しています。
また、ドキュメントを見た感じキーが変更される度に再フェッチするような感じなため
例2のようにするとnum変数が変更される度に再フェッチしてくれるみたいです。そのためこの機能は動的ページでidが変更される度にフェッチされるページで使用するケースが多いのかな？と感じました。

```js:example.js
//例1
const {data} = useQuery(['test'] ...);

//例2
const [num setNume] = useState(0)
const {data} = useQuery(['test',num] ...);

```

### クエリ関数
これは非同期でデータを取得する関数をここに設定します。
下記で記載しています`queryFn`などをよく見ます。

```js:example.js
const queryFn: async () => {
   const response = await fetch('/todos/' + todoId)
   if (!response.ok) {
     throw new Error('Network response was not ok')
   }
   return response.json()
}

const {data} = useQuery(['test'],querFn)

```

### オプション
これは記述の説明で記載しました`cacheTime`などです。
下記表ではよく使うものをまとめておきます。

| オプション名 | 説明                                                                                            | 
| ------------ | ----------------------------------------------------------------------------------------------- | 
| cacheTime    | キャッシュの保有時間を設定できる<br>指定がない場合は5分間。Infinity(永続的)な設定も可能。       | 
| staleTime    | 再フェッチ時に設定されている時間内はAPIなどからデータを持ってこず、キャッシュ値を返すことが可能 | 

## 最後に
SWRを実現するためにReactでは他にもuseSWRがありますが、TanStack Queryの方がDevtoolsがあったり、React以外にもVueやSolidでも提供されている点から発展の可能性が高いのかなと思っております。
また、Nuxt3での`useFetch`であったり`useAsyncData`も同じようにSWRを実現する機能が色々とでてきておりキャチアップはしっかりとしていければなと思っております。

明日は、@kouki_kubotaさんになります。
よろしくお願いします！