React Queryを利用したデータ取得・更新のサンプル

https://react-query.tanstack.com/

## インストール
```
npm install react-query
```

## まずQueryClientとQueryClientProviderを設定
App.tsx
```tsx
import { QueryClient, QueryClientProvider } from 'react-query'

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      retry: false,
      refetchOnWindowFocus: false,
    },
  },
})

const App = () => {
  return (
    <QueryClientProvider client={queryClient}>
     ...
    </QueryClientProvider>
  )
}
```
ここでdefaultOptionを設定すると全体に適用されます。
- `retry`
通信が失敗した場合、自動的にクエリを再試行するかどうか。（数値でリクエスト回数も指定可能）
https://react-query.tanstack.com/guides/query-retries#_top

- `refetchOnWindowFocus`
windowをfocusした際に自動的に再取得するかどうか
trueに設定すると、データが古い場合、windowのfocus時に再取得
"always"に設定すると、常にwindowのfocus時に再取得される。
https://react-query.tanstack.com/reference/useQuery#_top

## データの取得はuseQueryを使用する
- サンプルでJSONPlaceholderを使用してます。
- GET(/posts/1)
https://jsonplaceholder.typicode.com/

hooks/useQueryPosts.ts
```ts
import axios from 'axios'
import { useQuery } from 'react-query'

type Post = {
  userId: number,
  id: number
  title: string
  body:string
}

export const useQueryPosts = () => {
  const getPosts = async () => {
    const { data } = await axios.get<Post[]>(
      "https://jsonplaceholder.typicode.com/posts"
    )
    return data
  }

  return useQuery<Post[], Error>('posts', posts, {
    staleTime: 0,
    refetchOnWindowFocus: true,
    //cacheTime: 5000,
    //refetchInterval: 5000,
  })
}

```
- `staleTime`
デフォルトは0
キャッシュしたデータが古いとみなされるまでの時間をミリ秒単位で指定できます。
"Infinity"にするとデータが古いと判断されることがなくなります。
- `cacheTime`
デフォルトは 5 * 60 * 1000 (5分)
キャッシュする時間を残る時間をミリ秒単位で指定します。
"infinity"にすると残り続けます。
- `refetchInterval`
指定した数値で継続的にrefetchできます。(ポーリング)

## 使用例
```tsx
import { useQueryPosts } from '../hooks/useQueryPosts'

export const Posts = () => {
  const { data, isLoading, isError } = useQueryPosts()

  if (isLoading) return <div>Loading...</div>
  if (isError) return <div>Error</div>

  ...

}
```
returnされるデータ
https://react-query.tanstack.com/reference/useQuery#_top
- `data`
最後に解決したクエリー結果
デフォルトはundefined
- `error`
非同期関数からスローされたエラー内容
デフォルトはnull
- `isLoading`(Boolean)
ローディング中（キャッシュされたデータがなく現在フェッチ中）
- `isError`(Boolean)
クエリーの試行結果がエラーとなった場合

## データの更新はuseMutationを使用
- こちらもサンプルでJSONPlaceholderを使用してます。
- POST	 (.../posts)
- PUT	 (.../posts/1)
- DELETE (.../posts/1)

hooks/useMutatePost.ts
```ts
import axios from 'axios'
import { useMutation, useQueryClient } from 'react-query'

type Post = {
  userId: number,
  id: number
  title: string
  body:string
}

export const useMutatePost = () => {
  const queryClient = useQueryClient()

  const createPostMutation = useMutation(
    (post: Pick<Post, 'title' | 'body'>) =>
      axios.post<Post>('https://jsonplaceholder.typicode.com/posts', post),
    {
      onSuccess: (res) => {
        const previousPosts = queryClient.getQueryData<Post[]>('posts')
        if (previousPosts) {
          queryClient.setQueryData<Post[]>('posts', [
            ...previousPosts,
            res.data,
          ])
        }
      },
    }
  )
  const updatePostMutation = useMutation(
    (post<Omit, "userId">) =>
      axios.put<Post>(
        `https://jsonplaceholder.typicode.com/posts/${post.id}`,
        post
      ),
    {
      onSuccess: (res, variables) => {
        const previousPosts = queryClient.getQueryData<Post[]>('posts')
        if (previousPosts) {
          queryClient.setQueryData<Post[]>(
            'posts',
            previousPosts.map((post) =>
              post.id === variables.id ? res.data : post
            )
          )
        }
      },
    }
  )
  const deletePostMutation = useMutation(
    (id: number) =>
      axios.delete<Post>(`https://jsonplaceholder.typicode.com/posts/${id}`),
    {
      onSuccess: (res, variables) => {
        const previousPosts = queryClient.getQueryData<Post[]>('posts')
        if (previousPosts) {
          queryClient.setQueryData<Post[]>(
            'posts',
            previousPosts.filter((post) => post.id === variables)
          )
        }
      },
    }
  )
  return { createPostMutation, updatePostMutation, deletePostMutation }
}
```
https://react-query.tanstack.com/reference/useMutation
`getQueryData`で現在キャッシュされているデータを取得し、`setQueryData`で新たなデータをセットしてキャッシュを更新しています。

https://react-query.tanstack.com/guides/mutations


## 使用例

```tsx
export const PostCreate: FC = () => {
  const { createPostMutation } = useMutatePost()

  const postCreate = (post: Pick<Post, 'title' | 'body'>) => {
    createPostMutation.mutate(post)
  }
  if (createPostMutation.isLoading) return <div>Creating...</div>

  ...

}
```

## 最後に
まだまだ勉強不足なところが沢山あるので、また調べながら補足できればと思います。