パッケージインストール
$ npm i react-query
セットアップ
app.tsx
import React from 'react'
import { QueryClient, QueryClientProvider } from 'react-query'
const queryClient = new QueryClient({
defaultOptions: {
queries: {
suspense: true,
},
},
})
const App = () => {
return (
<QueryClientProvider client={queryClient}>
<SomethingComponent />
</QueryClientProvider>
)
}
export default MyApp
カスタムフックの作成
useQuery(データ取得用)
useFetchSomethingQuery
import { useQuery } from 'react-query'
type Something = {
name: string
email: string
}
type SomethingResponse = { data: Something[] }
// fetcher関数定義
const fetchGet = <T>(url: string): Promise<T> => {
const options = {
method: 'GET'
}
return fetch(url, options)
.then((res) => {
return res.json()
})
.catch((err) => {
throw new Error(err)
})
}
export const useFetchSomethingQuery = () => {
const url = 'https://api.something.com/something'
// useQueryの第一引数にはユニークなキーを設定
return useQuery('fetchSomething', () =>
fetchGet<SomethingResponse>(url)
)
}
useMutation(データ更新用)
import { useMutation, useQueryClient } from 'react-query'
type Something = {
name: string
email: string
}
type SomethingResponse = { data: { message: 'Success' } }
// fetcher関数定義
const fetchPost = <T>(url: string, data: Something): Promise<T> => {
const options = {
method: 'POST',
body: JSON.stringify(data),
}
return fetch(url, options)
.then((res) => {
return res.json()
})
.catch((err) => {
throw new Error(err)
})
}
export const usePostSomethingMutation = () => {
const queryClient = useQueryClient()
const url = 'https://api.something.com/something'
return useMutation((data: Something) => fetchPost<SomethingResponse>(url, data),
{
/*
成功時にuseQueryのkeyを設定することで、キャッシュを破棄して自動で再フェッチしてくれる
POSTした値を再フェッチしてリアルタイムで画面に描画したい時などに便利
*/
onSuccess: () => {
queryClient.invalidateQueries('fetchSomething')
},
}
)
}
コンポーネントで使う
GET
components/SomethingComponent
import React from 'react'
import useFetchSomethingQuery from '../api/useFetchSomethingQuery'
export const SomethingComponent = () => {
const { data, isLoading } = useFetchSomethingQuery()
const something = data?.data
if (isLoading) return 'Loading...'
return (
<div>
<h1>{something.name}</h1>
<p>{something.email}</p>
</div>
)
}
POST
components/SomethingComponent
import React from 'react'
import usePostSomethingMutation from '../api/usePostSomethingMutation'
export const SomethingComponent = () => {
const postMutation = usePostSomethingMutation()
const data = {
name: 'some',
email: 'thing@.com'
}
const handleSubmit((data) => {
// 成功時に何かしらの処理をしたい場合は第二引数に関数を渡す
postMutation.mutate(
data,
{ onSuccess: () => something() }
)
})
if (postMutation.isLoading) return 'Loading...'
return (
<div>
<button onClick={() => handleSubmit(data)}>
POST!
</button>
</div>
)
}
Tips
Suspenseを使う
-
defaultOptions
のqueries.suspense
をtrueに設定する必要がある - 親コンポーネントで非同期処理をキャッチすることができる
export const SomethingContainer = () => {
return (
<div>
<Suspense fallback={'Loading...'}>
<SomethingComponent />
</Suspense>
</div>
)
}
再フェッチするトリガーを指定したい
-
useQuery
の第一引数は配列にすることができる - 以下では
params
の値が変化したときに再フェッチを行う
export const useFetchSomethingQuery = () => {
const params = useParams()
const url = 'https://api.something.com/something'
return useQuery(['fetchSomething', params], () =>
fetchGet<SomethingResponse>(url)
)
}
参考資料